[Commits] 88d8314: # This is a combination of 4 commits.

Jan Lindström jan.lindstrom at mariadb.com
Thu Sep 8 15:20:06 EEST 2016


revision-id: 88d8314a6f7d7ba428d3685f62928a90966bba2b (mariadb-10.2.1-5-g88d8314)
parent(s): 2e814d4702d71a04388386a9f591d14a35980bfe
committer: Jan Lindström
timestamp: 2016-09-08 15:20:06 +0300
message:

# This is a combination of 4 commits.
# The first commit's message is:
Merge InnoDB 5.7 from mysql-5.7.14.

# This is the 2nd commit message:

Fix Windows compiler errors.

# This is the 3rd commit message:

Remove extra event_destroy()

# This is the 4th commit message:

Fixed crash on buffer_pool_resize() test case sys_vars.innodb-buffer-pool-resize-basic.test
accidentally created two threads for resize.

---
 include/my_base.h                                  |   13 +-
 include/my_handler_errors.h                        |   13 +-
 mysql-test/r/partition_innodb_plugin.result        |    1 +
 mysql-test/suite/innodb/r/innodb-mdev-7513.result  |    2 +
 .../suite/innodb/r/innodb-wl5522-debug-zip.result  |    1 +
 .../innodb/r/innodb_information_schema.result      |    8 +-
 mysql-test/suite/innodb/t/innodb-mdev-7513.test    |    4 +
 .../suite/innodb/t/innodb-wl5522-debug-zip.test    |    1 +
 mysql-test/suite/innodb/t/innodb.test              |    2 +-
 .../sys_vars/r/innodb_support_xa_basic.result      |   78 +-
 .../suite/sys_vars/r/innodb_support_xa_func.result |   16 +-
 mysql-test/t/partition_innodb_plugin.test          |    2 +
 mysql-test/t/row-checksum.opt                      |    1 +
 sql/handler.cc                                     |   11 +
 sql/share/errmsg-utf8.txt                          |   18 +
 storage/innobase/CMakeLists.txt                    |  405 +--
 storage/innobase/api/api0api.cc                    |   24 +-
 storage/innobase/api/api0misc.cc                   |   64 +-
 storage/innobase/btr/btr0btr.cc                    |  186 +-
 storage/innobase/btr/btr0bulk.cc                   |   37 +-
 storage/innobase/btr/btr0cur.cc                    |  228 +-
 storage/innobase/btr/btr0defragment.cc             |   27 +-
 storage/innobase/btr/btr0scrub.cc                  |    5 +-
 storage/innobase/btr/btr0sea.cc                    |   26 +-
 storage/innobase/buf/buf0buf.cc                    |  386 ++-
 storage/innobase/buf/buf0checksum.cc               |    6 +-
 storage/innobase/buf/buf0dblwr.cc                  |   13 +-
 storage/innobase/buf/buf0dump.cc                   |   44 +-
 storage/innobase/buf/buf0flu.cc                    |  176 +-
 storage/innobase/buf/buf0lru.cc                    |   57 +-
 storage/innobase/buf/buf0mtflu.cc                  |    2 +-
 storage/innobase/buf/buf0rea.cc                    |   13 +-
 storage/innobase/data/data0data.cc                 |    3 +-
 storage/innobase/dict/dict0boot.cc                 |    2 +-
 storage/innobase/dict/dict0crea.cc                 |  203 +-
 storage/innobase/dict/dict0defrag_bg.cc            |  403 +++
 storage/innobase/dict/dict0dict.cc                 |  318 ++-
 storage/innobase/dict/dict0load.cc                 |  280 +-
 storage/innobase/dict/dict0mem.cc                  |  285 +-
 storage/innobase/dict/dict0stats.cc                |  149 +-
 storage/innobase/dict/dict0stats_bg.cc             |  274 +-
 storage/innobase/fil/fil0crypt.cc                  |    2 +-
 storage/innobase/fil/fil0fil.cc                    | 1088 ++++---
 storage/innobase/fsp/fsp0file.cc                   |  132 +-
 storage/innobase/fsp/fsp0fsp.cc                    |  607 +++-
 storage/innobase/fsp/fsp0space.cc                  |   30 +-
 storage/innobase/fsp/fsp0sysspace.cc               |   27 +-
 storage/innobase/fts/fts0ast.cc                    |   34 +-
 storage/innobase/fts/fts0fts.cc                    |  103 +-
 storage/innobase/fts/fts0opt.cc                    |   54 +-
 storage/innobase/fts/fts0que.cc                    |   63 +-
 storage/innobase/gis/gis0rtree.cc                  |  139 +-
 storage/innobase/gis/gis0sea.cc                    |  123 +-
 storage/innobase/handler/ha_innodb.cc              | 2960 ++++++++++++--------
 storage/innobase/handler/ha_innodb.h               |  661 +++--
 storage/innobase/handler/ha_innopart.cc            |  245 +-
 storage/innobase/handler/ha_innopart.h             |   22 +-
 storage/innobase/handler/handler0alter.cc          | 1579 ++++++++---
 storage/innobase/handler/i_s.cc                    |  461 +--
 storage/innobase/ibuf/ibuf0ibuf.cc                 |   69 +-
 storage/innobase/include/api0api.h                 |    9 +-
 storage/innobase/include/btr0btr.h                 |   47 +-
 storage/innobase/include/btr0bulk.h                |    2 +-
 storage/innobase/include/btr0sea.h                 |    7 +
 storage/innobase/include/btr0sea.ic                |    6 +-
 storage/innobase/include/btr0types.h               |    2 +-
 storage/innobase/include/buf0buf.h                 |   65 +-
 storage/innobase/include/buf0buf.ic                |   71 +-
 storage/innobase/include/buf0checksum.h            |    7 +-
 storage/innobase/include/buf0dblwr.h               |    4 +-
 storage/innobase/include/buf0flu.h                 |   29 +-
 storage/innobase/include/buf0rea.h                 |    7 -
 storage/innobase/include/data0data.h               |   38 +-
 storage/innobase/include/data0data.ic              |   31 +-
 storage/innobase/include/db0err.h                  |   13 +-
 storage/innobase/include/dict0crea.h               |   14 +
 storage/innobase/include/dict0defrag_bg.h          |   93 +
 storage/innobase/include/dict0dict.h               |  137 +-
 storage/innobase/include/dict0dict.ic              |  101 +-
 storage/innobase/include/dict0load.h               |   10 +-
 storage/innobase/include/dict0mem.h                |  185 +-
 storage/innobase/include/dict0stats.h              |   36 +
 storage/innobase/include/dict0stats_bg.h           |   46 +-
 storage/innobase/include/dict0types.h              |   29 +-
 storage/innobase/include/dyn0buf.h                 |   22 +-
 storage/innobase/include/fil0crypt.ic              |    2 +-
 storage/innobase/include/fil0fil.h                 |  472 ++--
 storage/innobase/include/fsp0file.h                |   42 +-
 storage/innobase/include/fsp0fsp.h                 |  117 +-
 storage/innobase/include/fsp0fsp.ic                |   27 +-
 storage/innobase/include/fsp0space.h               |   21 +-
 storage/innobase/include/fsp0sysspace.h            |   24 +-
 storage/innobase/include/fsp0types.h               |   30 +-
 storage/innobase/include/fts0ast.h                 |    7 +
 storage/innobase/include/fts0fts.h                 |   95 +-
 storage/innobase/include/fts0priv.h                |   56 +-
 storage/innobase/include/fts0priv.ic               |   17 +-
 storage/innobase/include/fut0fut.h                 |    4 +-
 storage/innobase/include/gis0rtree.h               |   21 +-
 storage/innobase/include/ha0ha.h                   |    2 +-
 storage/innobase/include/ha_prototypes.h           |   16 +-
 storage/innobase/include/ibuf0ibuf.h               |    8 +-
 storage/innobase/include/lock0lock.h               |   48 +-
 storage/innobase/include/lock0prdt.h               |   23 +-
 storage/innobase/include/lock0priv.h               |   75 +-
 storage/innobase/include/log0log.h                 |   72 +-
 storage/innobase/include/log0log.ic                |    7 +-
 storage/innobase/include/log0recv.h                |   16 +-
 storage/innobase/include/mach0data.h               |   29 +-
 storage/innobase/include/mach0data.ic              |    2 +-
 storage/innobase/include/mem0mem.h                 |    2 +-
 storage/innobase/include/mem0mem.ic                |    2 +-
 storage/innobase/include/mtr0log.ic                |   24 +-
 storage/innobase/include/mtr0mtr.h                 |   44 +-
 storage/innobase/include/mtr0mtr.ic                |    2 +-
 storage/innobase/include/os0atomic.h               |   52 +-
 storage/innobase/include/os0atomic.ic              |   11 +-
 storage/innobase/include/os0file.h                 |  358 ++-
 storage/innobase/include/os0file.ic                |   11 +-
 storage/innobase/include/os0thread.h               |    9 +-
 storage/innobase/include/page0cur.h                |    3 +-
 storage/innobase/include/page0page.h               |   24 +-
 storage/innobase/include/page0types.h              |   15 +-
 storage/innobase/include/page0zip.h                |   52 +-
 storage/innobase/include/page0zip.ic               |    3 +-
 storage/innobase/include/pars0pars.h               |   18 +-
 storage/innobase/include/que0que.h                 |   16 +-
 storage/innobase/include/read0read.h               |    2 +-
 storage/innobase/include/read0types.h              |    4 +-
 storage/innobase/include/rem0cmp.h                 |   21 +-
 storage/innobase/include/rem0rec.h                 |   81 +-
 storage/innobase/include/rem0rec.ic                |    2 +-
 storage/innobase/include/row0ftsort.h              |    2 +-
 storage/innobase/include/row0ins.h                 |    8 +-
 storage/innobase/include/row0log.h                 |   17 +-
 storage/innobase/include/row0merge.h               |   86 +-
 storage/innobase/include/row0mysql.h               |   72 +-
 storage/innobase/include/row0purge.h               |    2 +-
 storage/innobase/include/row0row.h                 |   10 +-
 storage/innobase/include/row0sel.h                 |    9 +-
 storage/innobase/include/row0umod.h                |    2 +-
 storage/innobase/include/row0undo.h                |    4 +-
 storage/innobase/include/row0upd.h                 |   62 +-
 storage/innobase/include/row0vers.h                |    9 +-
 storage/innobase/include/srv0mon.h                 |    2 +-
 storage/innobase/include/srv0srv.h                 |   34 +-
 storage/innobase/include/srv0start.h               |   11 +
 storage/innobase/include/sync0arr.h                |    6 +-
 storage/innobase/include/sync0rw.h                 |   14 +-
 storage/innobase/include/sync0sync.h               |    5 +-
 storage/innobase/include/sync0types.h              |    7 +-
 storage/innobase/include/trx0rec.h                 |    4 +
 storage/innobase/include/trx0rseg.h                |    7 +-
 storage/innobase/include/trx0sys.h                 |   21 +-
 storage/innobase/include/trx0sys.ic                |    8 +-
 storage/innobase/include/trx0trx.h                 |   62 +-
 storage/innobase/include/trx0types.h               |    2 +-
 storage/innobase/include/trx0undo.h                |   11 +-
 storage/innobase/include/univ.i                    |   46 +-
 storage/innobase/include/ut0counter.h              |    8 +-
 storage/innobase/include/ut0crc32.h                |    2 +-
 storage/innobase/include/ut0dbg.h                  |    2 +-
 storage/innobase/include/ut0lst.h                  |    1 -
 storage/innobase/include/ut0mem.h                  |    2 +-
 storage/innobase/include/ut0new.h                  |   11 +-
 storage/innobase/include/ut0rnd.h                  |    2 +-
 storage/innobase/include/ut0rnd.ic                 |    2 +-
 storage/innobase/include/ut0ut.h                   |   35 +-
 storage/innobase/include/ut0wqueue.h               |    1 -
 storage/innobase/innodb.cmake                      |  254 +-
 storage/innobase/lock/lock0lock.cc                 |  940 +++----
 storage/innobase/lock/lock0prdt.cc                 |   33 +-
 storage/innobase/lock/lock0wait.cc                 |   14 +-
 storage/innobase/log/log0crypt.cc                  |    2 -
 storage/innobase/log/log0log.cc                    |  336 ++-
 storage/innobase/log/log0recv.cc                   |  847 +++++-
 storage/innobase/mtr/mtr0log.cc                    |   14 +-
 storage/innobase/mtr/mtr0mtr.cc                    |  193 +-
 storage/innobase/os/os0file.cc                     | 1238 +++++++-
 storage/innobase/os/os0sync.cc                     |  935 -------
 storage/innobase/os/os0thread.cc                   |   15 +-
 storage/innobase/page/page0zip.cc                  |   87 +-
 storage/innobase/pars/lexyy.cc                     |    2 +-
 storage/innobase/pars/pars0pars.cc                 |   21 +-
 storage/innobase/que/que0que.cc                    |   19 +-
 storage/innobase/rem/rem0cmp.cc                    |   58 +-
 storage/innobase/rem/rem0rec.cc                    |   15 +-
 storage/innobase/row/row0ftsort.cc                 |   30 +-
 storage/innobase/row/row0import.cc                 |  303 +-
 storage/innobase/row/row0ins.cc                    |  160 +-
 storage/innobase/row/row0log.cc                    |   51 +-
 storage/innobase/row/row0merge.cc                  |  252 +-
 storage/innobase/row/row0mysql.cc                  |  239 +-
 storage/innobase/row/row0purge.cc                  |   33 +
 storage/innobase/row/row0quiesce.cc                |  245 +-
 storage/innobase/row/row0row.cc                    |   16 +-
 storage/innobase/row/row0sel.cc                    |   82 +-
 storage/innobase/row/row0trunc.cc                  |   64 +-
 storage/innobase/row/row0uins.cc                   |    2 +-
 storage/innobase/row/row0umod.cc                   |   30 -
 storage/innobase/row/row0undo.cc                   |    2 +-
 storage/innobase/row/row0upd.cc                    |  313 ++-
 storage/innobase/row/row0vers.cc                   |  242 +-
 storage/innobase/srv/srv0conc.cc                   |   13 +
 storage/innobase/srv/srv0mon.cc                    |    7 +-
 storage/innobase/srv/srv0srv.cc                    |  168 +-
 storage/innobase/srv/srv0start.cc                  |  136 +-
 storage/innobase/sync/sync0arr.cc                  |   26 +-
 storage/innobase/sync/sync0debug.cc                |   17 +-
 storage/innobase/sync/sync0rw.cc                   |   46 +-
 storage/innobase/sync/sync0sync.cc                 |   10 +-
 storage/innobase/trx/trx0i_s.cc                    |    1 -
 storage/innobase/trx/trx0purge.cc                  |   13 +-
 storage/innobase/trx/trx0rec.cc                    |  161 +-
 storage/innobase/trx/trx0roll.cc                   |   18 +-
 storage/innobase/trx/trx0rseg.cc                   |   30 +-
 storage/innobase/trx/trx0sys.cc                    |  225 +-
 storage/innobase/trx/trx0trx.cc                    |  226 +-
 storage/innobase/trx/trx0undo.cc                   |   21 +-
 storage/innobase/ut/ut0crc32.cc                    |    2 +-
 storage/innobase/ut/ut0dbg.cc                      |    6 +-
 storage/innobase/ut/ut0new.cc                      |    4 +-
 storage/innobase/ut/ut0rnd.cc                      |    2 +-
 storage/innobase/ut/ut0ut.cc                       |   34 +-
 storage/innobase/ut/ut0wqueue.cc                   |    1 -
 225 files changed, 15418 insertions(+), 8611 deletions(-)

diff --git a/include/my_base.h b/include/my_base.h
index 1317639..af05336 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -499,7 +499,18 @@ enum ha_base_keytype {
 #define HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE 191 /* Too many words in a phrase */
 #define HA_ERR_DECRYPTION_FAILED  192 /* Table encrypted but
 						decypt failed */
-#define HA_ERR_LAST               192    /* Copy of last error nr */
+#define HA_ERR_FK_DEPTH_EXCEEDED  193 /* FK cascade depth exceeded */
+#define HA_MISSING_CREATE_OPTION       194  /* Option Missing during Create */
+#define HA_ERR_SE_OUT_OF_MEMORY        195  /* Out of memory in storage engine */
+#define HA_ERR_TABLE_CORRUPT           196  /* Table/Clustered index is corrupted. */
+#define HA_ERR_QUERY_INTERRUPTED       197  /* The query was interrupted */
+#define HA_ERR_TABLESPACE_MISSING      198  /* Missing Tablespace */
+#define HA_ERR_TABLESPACE_IS_NOT_EMPTY 199  /* Tablespace is not empty */
+#define HA_ERR_WRONG_FILE_NAME         200  /* Invalid Filename */
+#define HA_ERR_NOT_ALLOWED_COMMAND     201  /* Operation is not allowed */
+#define HA_ERR_COMPUTE_FAILED          202  /* Compute generated column value failed */
+#define HA_ERR_INNODB_READ_ONLY        203  /* InnoDB is in read only mode */
+#define HA_ERR_LAST                    203  /* Copy of last error nr * */
 
 /* Number of different errors */
 #define HA_ERR_ERRORS            (HA_ERR_LAST - HA_ERR_FIRST + 1)
diff --git a/include/my_handler_errors.h b/include/my_handler_errors.h
index 5af6a35..3d05fb7 100644
--- a/include/my_handler_errors.h
+++ b/include/my_handler_errors.h
@@ -95,7 +95,18 @@ static const char *handler_error_messages[]=
   "Disk full",
   "Incompatible key or row definition between the MariaDB .frm file and the information in the storage engine. You have to dump and restore the table to fix this",
   "Too many words in a FTS phrase or proximity search",
-  "Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match."
+  "Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.",
+  "Foreign key cascade delete/update exceeds max depth",
+  "Table storage engine found required create option missing",
+  "Out of memory in storage engine",
+  "Operation cannot be performed. The table is missing, corrupt or contains bad data.",
+  "Query execution was interrupted",
+  "Tablespace is missing for table",
+  "Tablespace is not empty",
+  "Incorrect File Name",
+  "Table storage engine found required create option missing",
+  "Compute virtual column value failed",
+  "InnoDB is in read only mode"
 };
 
 #endif /* MYSYS_MY_HANDLER_ERRORS_INCLUDED */
diff --git a/mysql-test/r/partition_innodb_plugin.result b/mysql-test/r/partition_innodb_plugin.result
index 35b1e31..16b5daa 100644
--- a/mysql-test/r/partition_innodb_plugin.result
+++ b/mysql-test/r/partition_innodb_plugin.result
@@ -1,3 +1,4 @@
+call mtr.add_suppression("InnoDB: Table .* does not exist in the InnoDB internal data dictionary .*");
 #
 # Bug#11766879/Bug#60106: DIFF BETWEEN # OF INDEXES IN MYSQL VS INNODB,
 #                         PARTITONING, ON INDEX CREATE
diff --git a/mysql-test/suite/innodb/r/innodb-mdev-7513.result b/mysql-test/suite/innodb/r/innodb-mdev-7513.result
index 55b4d34..91d6447 100644
--- a/mysql-test/suite/innodb/r/innodb-mdev-7513.result
+++ b/mysql-test/suite/innodb/r/innodb-mdev-7513.result
@@ -1,5 +1,6 @@
 call mtr.add_suppression("InnoDB: Cannot add field `.* in table .* because after adding it, the row size is .* which is greater than maximum allowed size (.*) for a record on index leaf page.");
 call mtr.add_suppression("Row size too large (> 8126)*");
+set GLOBAL innodb_strict_mode=OFF;
 CREATE TABLE t1 ( text1 TEXT,
 text2 TEXT,
 text3 TEXT,
@@ -202,4 +203,5 @@ INSERT INTO t1 VALUES ('abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef
 DELETE FROM t1 WHERE text1 = 'abcdef';
 SELECT * from t1;
 text1	text2	text3	text4	text5	text6	text7	text8	text9	text10	text11	text12	text13	text14	text15	text16	text17	text18	text19	text20	text21	text22	text23	text24	text25	text26	text27	text28	text29	text30	text31	text32	text33	text34	text35	text36	text37	text38	text39	text40	text41	text42	text43	text44	text45	text46	text47	text48	text49	text50	text51	text52	text53	text54	text55	text56	text57	text58	text59	text60	text61	text62	text63	text64	text65	text66	text67	text68	text69	text70	text71	text72	text73	text74	text75	text76	text77	text78	text79	text80	text81	text82	text83	text84	text85	text86	text87	text88	text89	text90	text91	text92	text93	text94	text95	text96	text97	text98	text99	text100	text101	text102	text103	text104	text105	text106	text107	text108	text109	text110	text111	text112	text113	text114	text115	text116	text117	text118	text119	text120	text121	text122	text123	text124	text125	text126	text127	text128	text129	text130	text131	text132	text133	text134	text135	text136	text137	t
 ext138	text139	text140	text141	text142	text143	text144	text145	text146	text147	text148	text149	text150	text151	text152	text153	text154	text155	text156	text157	text158	text159	text160	text161	text162	text163	text164	text165	text166	text167	text168	text169	text170	text171	text172	text173	text174	text175	text176	text177	text178	text179	text180	text181	text182	text183	text184	text185	text186	text187	text188	text189	text190	text191	text192	text193	text194	text195	text196	text197
+set GLOBAL innodb_strict_mode=DEFAULT;
 DROP TABLE t1;
diff --git a/mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result b/mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result
index ae4e96d..57edf7a 100644
--- a/mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result
+++ b/mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result
@@ -1,6 +1,7 @@
 call mtr.add_suppression("InnoDB: Tablespace for table .* is set as discarded.");
 call mtr.add_suppression("InnoDB: Cannot calculate statistics for table .* because the .ibd file is missing. Please refer to .* for how to resolve the issue.");
 call mtr.add_suppression("InnoDB: Error: Tablespace flags .* corrupted unused .*");
+call mtr.add_suppression("InnoDB: Tablespace flags: .* corrupted  in file: .* ");
 SET GLOBAL innodb_file_per_table = 1;
 SELECT @@innodb_file_per_table;
 @@innodb_file_per_table
diff --git a/mysql-test/suite/innodb/r/innodb_information_schema.result b/mysql-test/suite/innodb/r/innodb_information_schema.result
index 33dc50d..15c3af3 100644
--- a/mysql-test/suite/innodb/r/innodb_information_schema.result
+++ b/mysql-test/suite/innodb/r/innodb_information_schema.result
@@ -7,10 +7,10 @@ X	RECORD	`test`.```t'\"_str`	PRIMARY	4	'3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a
 X	RECORD	`test`.```t'\"_str`	PRIMARY	4	'3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\'
 X	RECORD	`test`.```t'\"_str`	PRIMARY	5	'4', 'abc', '\0abc', 'abc\0', 'a\0bc', 'a\0bc\0', 'a\0bc\0\0'
 X	RECORD	`test`.```t'\"_str`	PRIMARY	5	'4', 'abc', '\0abc', 'abc\0', 'a\0bc', 'a\0bc\0', 'a\0bc\0\0'
-X	RECORD	`test`.`t_max`	PRIMARY	2	127.000000, 140517642401116, 32767.000000, 140517642401147, 8388607.000000, 140517642401180, 2147483647.000000, 140517642401216, 9223372036854775808.000000, 140517642401261
-X	RECORD	`test`.`t_max`	PRIMARY	2	127.000000, 140517642401116, 32767.000000, 140517642401147, 8388607.000000, 140517642401180, 2147483647.000000, 140517642401216, 9223372036854775808.000000, 140517642401261
-X	RECORD	`test`.`t_min`	PRIMARY	2	18446744073709551616.000000, 140517642401133, 18446744073709518848.000000, 140517642401179, 18446744073701163008.000000, 140517642401225, 18446744071562067968.000000, 140517642401271, 9223372036854775808.000000, 140517642401316
-X	RECORD	`test`.`t_min`	PRIMARY	2	18446744073709551616.000000, 140517642401133, 18446744073709518848.000000, 140517642401179, 18446744073701163008.000000, 140517642401225, 18446744071562067968.000000, 140517642401271, 9223372036854775808.000000, 140517642401316
+X	RECORD	`test`.`t_min`	PRIMARY	2	-128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0
+X	RECORD	`test`.`t_min`	PRIMARY	2	-128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0
+X	RECORD	`test`.`t_max`	PRIMARY	2	127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615
+X	RECORD	`test`.`t_max`	PRIMARY	2	127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615
 X	RECORD	`test`.```t'\"_str`	PRIMARY	1	supremum pseudo-record
 X	RECORD	`test`.```t'\"_str`	PRIMARY	1	supremum pseudo-record
 lock_table	COUNT(*)
diff --git a/mysql-test/suite/innodb/t/innodb-mdev-7513.test b/mysql-test/suite/innodb/t/innodb-mdev-7513.test
index 88f941e..cc2e7a9 100644
--- a/mysql-test/suite/innodb/t/innodb-mdev-7513.test
+++ b/mysql-test/suite/innodb/t/innodb-mdev-7513.test
@@ -6,6 +6,8 @@
 call mtr.add_suppression("InnoDB: Cannot add field `.* in table .* because after adding it, the row size is .* which is greater than maximum allowed size (.*) for a record on index leaf page.");
 call mtr.add_suppression("Row size too large (> 8126)*");
 
+set GLOBAL innodb_strict_mode=OFF;
+
 --disable_warnings
 CREATE TABLE t1 ( text1 TEXT,
 text2 TEXT,
@@ -217,5 +219,7 @@ DELETE FROM t1 WHERE text1 = 'abcdef';
 SELECT * from t1;
 --enable_warnings
 
+set GLOBAL innodb_strict_mode=DEFAULT;
+
 DROP TABLE t1;
 
diff --git a/mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test b/mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test
index c61d10e..762b475 100644
--- a/mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test
+++ b/mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test
@@ -20,6 +20,7 @@
 call mtr.add_suppression("InnoDB: Tablespace for table .* is set as discarded.");
 call mtr.add_suppression("InnoDB: Cannot calculate statistics for table .* because the .ibd file is missing. Please refer to .* for how to resolve the issue.");
 call mtr.add_suppression("InnoDB: Error: Tablespace flags .* corrupted unused .*");
+call mtr.add_suppression("InnoDB: Tablespace flags: .* corrupted  in file: .* ");
 
 let MYSQLD_DATADIR =`SELECT @@datadir`;
 let $innodb_file_per_table = `SELECT @@innodb_file_per_table`;
diff --git a/mysql-test/suite/innodb/t/innodb.test b/mysql-test/suite/innodb/t/innodb.test
index 79a00c2..d129e86 100644
--- a/mysql-test/suite/innodb/t/innodb.test
+++ b/mysql-test/suite/innodb/t/innodb.test
@@ -1141,7 +1141,7 @@ insert into t1 values
 (244, 243), (245, 244), (246, 245), (247, 246),
 (248, 247), (249, 248), (250, 249), (251, 250),
 (252, 251), (253, 252), (254, 253), (255, 254);
---error 1296,1451
+--error 4029,1451
 delete from t1 where id=0;
 delete from t1 where id=255;
 --error 0,1451
diff --git a/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result b/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result
index 754b093..8384ee3 100644
--- a/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result
+++ b/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result
@@ -8,17 +8,27 @@ SELECT @global_start_value;
 1
 '#--------------------FN_DYNVARS_046_01------------------------#'
 SET @@session.innodb_support_xa = 0;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SET @@session.innodb_support_xa = DEFAULT;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SELECT @@session.innodb_support_xa;
 @@session.innodb_support_xa
 1
 SET @@global.innodb_support_xa = 0;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SET @@global.innodb_support_xa = DEFAULT;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SELECT @@global.innodb_support_xa;
 @@global.innodb_support_xa
 1
 '#---------------------FN_DYNVARS_046_02-------------------------#'
 SET innodb_support_xa = 1;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SELECT @@innodb_support_xa;
 @@innodb_support_xa
 1
@@ -29,27 +39,39 @@ ERROR 42S02: Unknown table 'local' in field list
 SELECT global.innodb_support_xa;
 ERROR 42S02: Unknown table 'global' in field list
 SET session innodb_support_xa = 0;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SELECT @@session.innodb_support_xa;
 @@session.innodb_support_xa
-0
+1
 SET global innodb_support_xa = 0;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SELECT @@global.innodb_support_xa;
 @@global.innodb_support_xa
-0
+1
 '#--------------------FN_DYNVARS_046_03------------------------#'
 SET @@session.innodb_support_xa = 0;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SELECT @@session.innodb_support_xa;
 @@session.innodb_support_xa
-0
+1
 SET @@session.innodb_support_xa = 1;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SELECT @@session.innodb_support_xa;
 @@session.innodb_support_xa
 1
 SET @@global.innodb_support_xa = 0;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SELECT @@global.innodb_support_xa;
 @@global.innodb_support_xa
-0
+1
 SET @@global.innodb_support_xa = 1;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SELECT @@global.innodb_support_xa;
 @@global.innodb_support_xa
 1
@@ -67,9 +89,11 @@ ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'TR
 SET @@session.innodb_support_xa = ÕN;
 ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÕN'
 SET @@session.innodb_support_xa = OF;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SELECT @@session.innodb_support_xa;
 @@session.innodb_support_xa
-0
+1
 SET @@session.innodb_support_xa = ÓFF;
 ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÓFF'
 SET @@global.innodb_support_xa = -1;
@@ -88,18 +112,26 @@ ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'TR
 SET @@global.innodb_support_xa = ÕN;
 ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÕN'
 SET @@global.innodb_support_xa = OF;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SELECT @@global.innodb_support_xa;
 @@global.innodb_support_xa
-0
+1
 SET @@global.innodb_support_xa = ÓFF;
 ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÓFF'
 '#-------------------FN_DYNVARS_046_05----------------------------#'
 SET @@global.innodb_support_xa = 0;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SET @@session.innodb_support_xa = 1;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SELECT @@global.innodb_support_xa AS res_is_0;
 res_is_0
-0
+1
 SET @@global.innodb_support_xa = 0;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SELECT @@session.innodb_support_xa AS res_is_1;
 res_is_1
 1
@@ -112,11 +144,11 @@ VARIABLE_VALUE
 1
 SELECT @@global.innodb_support_xa;
 @@global.innodb_support_xa
-0
+1
 SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
 WHERE VARIABLE_NAME='innodb_support_xa';
 VARIABLE_VALUE
-OFF
+ON
 '#----------------------FN_DYNVARS_046_07------------------------#'
 SELECT IF(@@session.innodb_support_xa, "ON", "OFF") =
 VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES
@@ -133,43 +165,63 @@ VARIABLE_VALUE
 ON
 '#---------------------FN_DYNVARS_046_08-------------------------#'
 SET @@session.innodb_support_xa = OFF;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SELECT @@session.innodb_support_xa;
 @@session.innodb_support_xa
-0
+1
 SET @@session.innodb_support_xa = ON;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SELECT @@session.innodb_support_xa;
 @@session.innodb_support_xa
 1
 SET @@global.innodb_support_xa = OFF;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SELECT @@global.innodb_support_xa;
 @@global.innodb_support_xa
-0
+1
 SET @@global.innodb_support_xa = ON;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SELECT @@global.innodb_support_xa;
 @@global.innodb_support_xa
 1
 '#---------------------FN_DYNVARS_046_09----------------------#'
 SET @@session.innodb_support_xa = TRUE;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SELECT @@session.innodb_support_xa;
 @@session.innodb_support_xa
 1
 SET @@session.innodb_support_xa = FALSE;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SELECT @@session.innodb_support_xa;
 @@session.innodb_support_xa
-0
+1
 SET @@global.innodb_support_xa = TRUE;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SELECT @@global.innodb_support_xa;
 @@global.innodb_support_xa
 1
 SET @@global.innodb_support_xa = FALSE;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 SELECT @@global.innodb_support_xa;
 @@global.innodb_support_xa
-0
+1
 SET @@session.innodb_support_xa = @session_start_value;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SELECT @@session.innodb_support_xa;
 @@session.innodb_support_xa
 1
 SET @@global.innodb_support_xa = @global_start_value;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SELECT @@global.innodb_support_xa;
 @@global.innodb_support_xa
 1
diff --git a/mysql-test/suite/sys_vars/r/innodb_support_xa_func.result b/mysql-test/suite/sys_vars/r/innodb_support_xa_func.result
index 7291b60..d86cf89 100644
--- a/mysql-test/suite/sys_vars/r/innodb_support_xa_func.result
+++ b/mysql-test/suite/sys_vars/r/innodb_support_xa_func.result
@@ -1,21 +1,27 @@
 '#--------------------FN_DYNVARS_046_01-------------------------#'
 SET @@global.innodb_support_xa = OFF;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 connect  con1,localhost,root,,,,;
 connection con1;
 SELECT @@global.innodb_support_xa;
 @@global.innodb_support_xa
-0
+1
 SELECT @@session.innodb_support_xa;
 @@session.innodb_support_xa
-0
+1
 disconnect con1;
 '#--------------------FN_DYNVARS_046_01-------------------------#'
 connection default;
 SET @@global.innodb_support_xa = 1;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 drop table if exists t1, t2;
 create table t1 (a int) engine=innodb;
 '---check when innodb_support_xa is 1---'
 SET @@innodb_support_xa = 1;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 xa start 'test1';
 INSERT t1 values (10);
 xa end 'test1';
@@ -25,6 +31,8 @@ SELECT * from t1;
 a
 '---check when innodb_support_xa is 0---'
 SET @@innodb_support_xa = 0;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
 xa start 'test1';
 INSERT t1 values (10);
 xa end 'test1';
@@ -34,7 +42,11 @@ SELECT * from t1;
 a
 '------general xa testing--------'
 SET @@global.innodb_support_xa = 1;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 SET @@innodb_support_xa = 1;
+Warnings:
+Warning	131	Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
 xa start 'testa','testb';
 INSERT t1 values (30);
 COMMIT;
diff --git a/mysql-test/t/partition_innodb_plugin.test b/mysql-test/t/partition_innodb_plugin.test
index 3a3ae25..a514736 100644
--- a/mysql-test/t/partition_innodb_plugin.test
+++ b/mysql-test/t/partition_innodb_plugin.test
@@ -3,6 +3,8 @@
 
 let $MYSQLD_DATADIR= `SELECT @@datadir`;
 
+call mtr.add_suppression("InnoDB: Table .* does not exist in the InnoDB internal data dictionary .*");
+
 --echo #
 --echo # Bug#11766879/Bug#60106: DIFF BETWEEN # OF INDEXES IN MYSQL VS INNODB,
 --echo #                         PARTITONING, ON INDEX CREATE
diff --git a/mysql-test/t/row-checksum.opt b/mysql-test/t/row-checksum.opt
new file mode 100644
index 0000000..977b569
--- /dev/null
+++ b/mysql-test/t/row-checksum.opt
@@ -0,0 +1 @@
+--loose-innodb-strict-mode=off
diff --git a/sql/handler.cc b/sql/handler.cc
index 3fbd1b3..875e3d5 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -370,6 +370,17 @@ int ha_init_errors(void)
   SETMSG(HA_ERR_TABLE_IN_FK_CHECK,	ER_DEFAULT(ER_TABLE_IN_FK_CHECK));
   SETMSG(HA_ERR_DISK_FULL,              ER_DEFAULT(ER_DISK_FULL));
   SETMSG(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE,  "Too many words in a FTS phrase or proximity search");
+  SETMSG(HA_ERR_FK_DEPTH_EXCEEDED,      ER_DEFAULT(ER_FK_DEPTH_EXCEEDED));
+  SETMSG(HA_MISSING_CREATE_OPTION,      ER_DEFAULT(ER_MISSING_HA_CREATE_OPTION));
+  SETMSG(HA_ERR_SE_OUT_OF_MEMORY,       ER_DEFAULT(ER_ENGINE_OUT_OF_MEMORY));
+  SETMSG(HA_ERR_TABLE_CORRUPT,          ER_DEFAULT(ER_TABLE_CORRUPT));
+  SETMSG(HA_ERR_QUERY_INTERRUPTED,      ER_DEFAULT(ER_QUERY_INTERRUPTED));
+  SETMSG(HA_ERR_TABLESPACE_MISSING,     ER_DEFAULT(ER_TABLESPACE_MISSING));
+  SETMSG(HA_ERR_TABLESPACE_IS_NOT_EMPTY,ER_DEFAULT(ER_TABLESPACE_IS_NOT_EMPTY));
+  SETMSG(HA_ERR_WRONG_FILE_NAME,        ER_DEFAULT(ER_WRONG_FILE_NAME));
+  SETMSG(HA_ERR_NOT_ALLOWED_COMMAND,    ER_DEFAULT(ER_NOT_ALLOWED_COMMAND));
+  SETMSG(HA_ERR_COMPUTE_FAILED,         "Compute virtual column value failed");
+  SETMSG(HA_ERR_INNODB_READ_ONLY,       ER_DEFAULT(ER_INNODB_READ_ONLY));
 
   /* Register the error messages for use with my_error(). */
   return my_error_register(get_handler_errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 8dfa519..7c3c4ab 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7214,3 +7214,21 @@ ER_CALCULATING_DEFAULT_VALUE
         eng "Got an error when calculating default value for %`s"
 ER_EXPRESSION_REFERS_TO_UNINIT_FIELD 01000
         eng "Expression for field %`-.64s is refering to uninitialized field %`s"
+ER_BUFPOOL_RESIZE_INPROGRESS
+        eng "Another buffer pool resize is already in progress."
+ER_CANNOT_DISCARD_TEMPORARY_TABLE
+        eng "Cannot DISCARD/IMPORT tablespace associated with temporary table"
+ER_FK_DEPTH_EXCEEDED
+        eng "Foreign key cascade delete/update exceeds max depth of %d."
+ER_INNODB_FORCED_RECOVERY
+        eng "Operation not allowed when innodb_forced_recovery > 0."
+ER_TABLE_REFERENCED
+        eng "Cannot complete the operation because table is referenced by another connection."
+ER_TABLESPACE_IS_NOT_EMPTY
+        eng "Tablespace `%-.192s` is not empty."
+ER_MISSING_HA_CREATE_OPTION
+        eng "Table storage engine '%-.64s' found required create option missing"
+ER_ENGINE_OUT_OF_MEMORY
+        eng "Out of memory in storage engine '%-.64s'."
+ER_WRONG_FILE_NAME
+        eng "Incorrect File Name '%s'."
diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt
index b835d6b..44b1cfa 100644
--- a/storage/innobase/CMakeLists.txt
+++ b/storage/innobase/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2016, 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
@@ -30,351 +31,7 @@ MYSQL_CHECK_LZMA()
 MYSQL_CHECK_BZIP2()
 MYSQL_CHECK_SNAPPY()
 
-IF(CMAKE_CROSSCOMPILING)
-  # Use CHECK_C_SOURCE_COMPILES instead of CHECK_C_SOURCE_RUNS when
-  # cross-compiling. Not as precise, but usually good enough.
-  # This only make sense for atomic tests in this file, this trick doesn't
-  # work in a general case.
-  MACRO(CHECK_C_SOURCE SOURCE VAR)
-    CHECK_C_SOURCE_COMPILES("${SOURCE}" "${VAR}")
-  ENDMACRO()
-ELSE()
-  MACRO(CHECK_C_SOURCE SOURCE VAR)
-    CHECK_C_SOURCE_RUNS("${SOURCE}" "${VAR}")
-  ENDMACRO()
-ENDIF()
-
-# OS tests
-IF(UNIX)
-  IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
-    CHECK_INCLUDE_FILES (libaio.h HAVE_LIBAIO_H)
-    CHECK_LIBRARY_EXISTS(aio io_queue_init "" HAVE_LIBAIO)
-    ADD_DEFINITIONS("-DUNIV_LINUX -D_GNU_SOURCE=1")
-    IF(HAVE_LIBAIO_H AND HAVE_LIBAIO)
-      ADD_DEFINITIONS(-DLINUX_NATIVE_AIO=1)
-      LINK_LIBRARIES(aio)
-    ENDIF()
-    IF(HAVE_LIBNUMA)
-      LINK_LIBRARIES(numa)
-    ENDIF()
-  ELSEIF(CMAKE_SYSTEM_NAME MATCHES "HP*")
-    ADD_DEFINITIONS("-DUNIV_HPUX")
-  ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "AIX")
-    ADD_DEFINITIONS("-DUNIV_AIX")
-  ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
-    ADD_DEFINITIONS("-DUNIV_SOLARIS")
-  ENDIF()
-ENDIF()
-
-IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
-# After: WL#5825 Using C++ Standard Library with MySQL code
-#       we no longer use -fno-exceptions
-#	SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
-ENDIF()
-
-# Enable InnoDB's UNIV_DEBUG and UNIV_SYNC_DEBUG in debug builds
-SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DUNIV_DEBUG -DUNIV_SYNC_DEBUG")
-
-# Add -Wconversion if compiling with GCC
-## As of Mar 15 2011 this flag causes 3573+ warnings. If you are reading this
-## please fix them and enable the following code:
-#IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
-#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wconversion")
-#ENDIF()
-
-CHECK_FUNCTION_EXISTS(sched_getcpu  HAVE_SCHED_GETCPU)
-IF(HAVE_SCHED_GETCPU)
-  ADD_DEFINITIONS(-DHAVE_SCHED_GETCPU)
-ENDIF()
-
-IF(NOT MSVC)
-  # either define HAVE_IB_GCC_ATOMIC_BUILTINS or not
-  # workaround for gcc 4.1.2 RHEL5/x86, gcc atomic ops only work under -march=i686
-  IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "i686" AND CMAKE_COMPILER_IS_GNUCC AND
-     CMAKE_C_COMPILER_VERSION VERSION_LESS "4.1.3")
-    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=i686")
-    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i686")
-  ENDIF()
-  CHECK_C_SOURCE(
-  "
-  int main()
-  {
-    long	x;
-    long	y;
-    long	res;
-
-    x = 10;
-    y = 123;
-    res = __sync_bool_compare_and_swap(&x, x, y);
-    if (!res || x != y) {
-      return(1);
-    }
-
-    x = 10;
-    y = 123;
-    res = __sync_bool_compare_and_swap(&x, x + 1, y);
-    if (res || x != 10) {
-      return(1);
-    }
-    x = 10;
-    y = 123;
-    res = __sync_add_and_fetch(&x, y);
-    if (res != 123 + 10 || x != 123 + 10) {
-      return(1);
-    }
-    return(0);
-  }"
-  HAVE_IB_GCC_ATOMIC_BUILTINS
-  )
-  CHECK_C_SOURCE(
-  "
-  int main()
-  {
-    long	res;
-    char	c;
-
-    c = 10;
-    res = __sync_lock_test_and_set(&c, 123);
-    if (res != 10 || c != 123) {
-      return(1);
-    }
-    return(0);
-  }"
-  HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE
-  )
-  CHECK_C_SOURCE(
-  "#include<stdint.h>
-  int main()
-  {
-    int64_t	x,y,res;
-
-    x = 10;
-    y = 123;
-    res = __sync_sub_and_fetch(&y, x);
-    if (res != y || y != 113) {
-      return(1);
-    }
-    res = __sync_add_and_fetch(&y, x);
-    if (res != y || y != 123) {
-      return(1);
-    }
-    return(0);
-  }"
-  HAVE_IB_GCC_ATOMIC_BUILTINS_64
-  )
-  CHECK_C_SOURCE(
-  "#include<stdint.h>
-  int main()
-  {
-    __sync_synchronize();
-    return(0);
-  }"
-  HAVE_IB_GCC_SYNC_SYNCHRONISE
-  )
-  CHECK_C_SOURCE(
-  "#include<stdint.h>
-  int main()
-  {
-    __atomic_thread_fence(__ATOMIC_ACQUIRE);
-    __atomic_thread_fence(__ATOMIC_RELEASE);
-    return(0);
-  }"
-  HAVE_IB_GCC_ATOMIC_THREAD_FENCE
-  )
-  CHECK_C_SOURCE(
-  "#include<stdint.h>
-  int main()
-  {
-    unsigned char	c;
-
-    __atomic_test_and_set(&c, __ATOMIC_ACQUIRE);
-    __atomic_clear(&c, __ATOMIC_RELEASE);
-    return(0);
-  }"
-  HAVE_IB_GCC_ATOMIC_TEST_AND_SET
-  )
-
-IF(HAVE_IB_GCC_ATOMIC_BUILTINS)
- ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS=1)
-ENDIF()
-
-IF(HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE)
- ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS_BYTE=1)
-ENDIF()
-
-IF(HAVE_IB_GCC_ATOMIC_BUILTINS_64)
- ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS_64=1)
-ENDIF()
-
-IF(HAVE_IB_GCC_SYNC_SYNCHRONISE)
- ADD_DEFINITIONS(-DHAVE_IB_GCC_SYNC_SYNCHRONISE=1)
-ENDIF()
-
-IF(HAVE_IB_GCC_ATOMIC_THREAD_FENCE)
- ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_THREAD_FENCE=1)
-ENDIF()
-
-IF(HAVE_IB_GCC_ATOMIC_TEST_AND_SET)
- ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_TEST_AND_SET=1)
-ENDIF()
-
-# either define HAVE_IB_ATOMIC_PTHREAD_T_GCC or not
-CHECK_C_SOURCE(
-"
-#include <pthread.h>
-#include <string.h>
-
-int main() {
-  pthread_t       x1;
-  pthread_t       x2;
-  pthread_t       x3;
-
-  memset(&x1, 0x0, sizeof(x1));
-  memset(&x2, 0x0, sizeof(x2));
-  memset(&x3, 0x0, sizeof(x3));
-
-  __sync_bool_compare_and_swap(&x1, x2, x3);
-
-  return(0);
-}"
-HAVE_IB_ATOMIC_PTHREAD_T_GCC)
-
-IF(HAVE_IB_ATOMIC_PTHREAD_T_GCC)
-  ADD_DEFINITIONS(-DHAVE_IB_ATOMIC_PTHREAD_T_GCC=1)
-ENDIF()
-
-CHECK_CXX_SOURCE_COMPILES("struct t1{ int a; char *b; }; struct t1 c= { .a=1, .b=0 }; main() { }" HAVE_C99_INITIALIZERS)
-IF(HAVE_C99_INITIALIZERS)
-  ADD_DEFINITIONS(-DHAVE_C99_INITIALIZERS)
-ENDIF()
-
-ENDIF(NOT MSVC)
-
-CHECK_FUNCTION_EXISTS(vasprintf  HAVE_VASPRINTF)
-
-# Solaris atomics
-IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
-  CHECK_FUNCTION_EXISTS(atomic_cas_ulong  HAVE_ATOMIC_CAS_ULONG)
-  CHECK_FUNCTION_EXISTS(atomic_cas_32 HAVE_ATOMIC_CAS_32)
-  CHECK_FUNCTION_EXISTS(atomic_cas_64 HAVE_ATOMIC_CAS_64)
-  CHECK_FUNCTION_EXISTS(atomic_add_long_nv HAVE_ATOMIC_ADD_LONG_NV)
-  CHECK_FUNCTION_EXISTS(atomic_swap_uchar HAVE_ATOMIC_SWAP_UCHAR)
-  IF(HAVE_ATOMIC_CAS_ULONG AND
-     HAVE_ATOMIC_CAS_32 AND
-     HAVE_ATOMIC_CAS_64 AND
-     HAVE_ATOMIC_ADD_LONG_NV AND
-     HAVE_ATOMIC_SWAP_UCHAR)
-    SET(HAVE_IB_SOLARIS_ATOMICS 1)
-  ENDIF()
-
-  IF(HAVE_IB_SOLARIS_ATOMICS)
-    ADD_DEFINITIONS(-DHAVE_IB_SOLARIS_ATOMICS=1)
-  ENDIF()
-
-  # either define HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS or not
-  CHECK_C_SOURCE_COMPILES(
-  "   #include <pthread.h>
-      #include <string.h>
-
-      int main(int argc, char** argv) {
-        pthread_t       x1;
-        pthread_t       x2;
-        pthread_t       x3;
-
-        memset(&x1, 0x0, sizeof(x1));
-        memset(&x2, 0x0, sizeof(x2));
-        memset(&x3, 0x0, sizeof(x3));
-
-        if (sizeof(pthread_t) == 4) {
-
-          atomic_cas_32(&x1, x2, x3);
-
-        } else if (sizeof(pthread_t) == 8) {
-
-          atomic_cas_64(&x1, x2, x3);
-
-        } else {
-
-          return(1);
-        }
-
-      return(0);
-    }
-  " HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS)
-  CHECK_C_SOURCE_COMPILES(
-  "#include <mbarrier.h>
-  int main() {
-    __machine_r_barrier();
-    __machine_w_barrier();
-    return(0);
-  }"
-  HAVE_IB_MACHINE_BARRIER_SOLARIS)
-
-  IF(HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS)
-    ADD_DEFINITIONS(-DHAVE_IB_ATOMIC_PTHREAD_T_SOLARIS=1)
-  ENDIF()
-  IF(HAVE_IB_MACHINE_BARRIER_SOLARIS)
-    ADD_DEFINITIONS(-DHAVE_IB_MACHINE_BARRIER_SOLARIS=1)
-  ENDIF()
-ENDIF()
-
-
-IF(UNIX)
-# this is needed to know which one of atomic_cas_32() or atomic_cas_64()
-# to use in the source
-SET(CMAKE_EXTRA_INCLUDE_FILES pthread.h)
-CHECK_TYPE_SIZE(pthread_t SIZEOF_PTHREAD_T)
-SET(CMAKE_EXTRA_INCLUDE_FILES)
-ENDIF()
-
-IF(SIZEOF_PTHREAD_T)
-  ADD_DEFINITIONS(-DSIZEOF_PTHREAD_T=${SIZEOF_PTHREAD_T})
-ENDIF()
-
-IF(MSVC)
-  ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS)
-  ADD_DEFINITIONS(-DHAVE_WINDOWS_MM_FENCE)
-ENDIF()
-
-SET(MUTEXTYPE "event" CACHE STRING "Mutex type: event, sys or futex")
-
-IF(MUTEXTYPE MATCHES "event")
-  ADD_DEFINITIONS(-DMUTEX_EVENT)
-ELSEIF(MUTEXTYPE MATCHES "futex" AND DEFINED HAVE_IB_LINUX_FUTEX)
-  ADD_DEFINITIONS(-DMUTEX_FUTEX)
-ELSE()
-   ADD_DEFINITIONS(-DMUTEX_SYS)
-ENDIF()
- 
-# Include directories under innobase
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innobase/include
-		    ${CMAKE_SOURCE_DIR}/storage/innobase/handler)
-
-# Sun Studio bug with -xO2
-IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro"
-	AND CMAKE_CXX_FLAGS_RELEASE MATCHES "O2"
-	AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
-	# Sun Studio 12 crashes with -xO2 flag, but not with higher optimization
-	# -xO3
-	SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/rem/rem0rec.cc
-    PROPERTIES COMPILE_FLAGS -xO3)
-ENDIF()
-
-# Removing compiler optimizations for innodb/mem/* files on 64-bit Windows
-# due to 64-bit compiler error, See MySQL Bug #19424, #36366, #34297
-IF (MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
-	SET_SOURCE_FILES_PROPERTIES(mem/mem0mem.cc mem/mem0pool.cc
-				    PROPERTIES COMPILE_FLAGS -Od)
-ENDIF()
-
-IF(MSVC)
-  # Avoid "unreferenced label" warning in generated file
-  GET_FILENAME_COMPONENT(_SRC_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
-  SET_SOURCE_FILES_PROPERTIES(${_SRC_DIR}/pars/pars0grm.c
-          PROPERTIES COMPILE_FLAGS "/wd4102")
-  SET_SOURCE_FILES_PROPERTIES(${_SRC_DIR}/pars/lexyy.c
-          PROPERTIES COMPILE_FLAGS "/wd4003")
-ENDIF()
+INCLUDE(innodb.cmake)
 
 SET(INNOBASE_SOURCES
 	api/api0api.cc
@@ -404,7 +61,7 @@ SET(INNOBASE_SOURCES
 	dict/dict0mem.cc
 	dict/dict0stats.cc
 	dict/dict0stats_bg.cc
-#	dyn/dyn0dyn.cc
+	dict/dict0defrag_bg.cc
 	eval/eval0eval.cc
 	eval/eval0proc.cc
 	fil/fil0fil.cc
@@ -425,34 +82,32 @@ SET(INNOBASE_SOURCES
 	fts/fts0config.cc
 	fts/fts0opt.cc
 	fts/fts0pars.cc
-	fts/fts0plugin.cc
 	fts/fts0que.cc
 	fts/fts0sql.cc
 	fts/fts0tlex.cc
 	gis/gis0geo.cc
 	gis/gis0rtree.cc
 	gis/gis0sea.cc
+	fts/fts0plugin.cc
 	handler/ha_innodb.cc
 #	handler/ha_innopart.cc
 	handler/handler0alter.cc
 	handler/i_s.cc
 	ibuf/ibuf0ibuf.cc
 	lock/lock0iter.cc
-	lock/lock0lock.cc
 	lock/lock0prdt.cc
+	lock/lock0lock.cc
 	lock/lock0wait.cc
 	log/log0log.cc
 	log/log0recv.cc
 	log/log0crypt.cc
 	mach/mach0data.cc
 	mem/mem0mem.cc
-#	mem/mem0pool.cc
 	mtr/mtr0log.cc
 	mtr/mtr0mtr.cc
-	os/os0event.cc
 	os/os0file.cc
 	os/os0proc.cc
-#	os/os0sync.cc
+	os/os0event.cc
 	os/os0thread.cc
 	page/page0cur.cc
 	page/page0page.cc
@@ -488,8 +143,8 @@ SET(INNOBASE_SOURCES
 	srv/srv0srv.cc
 	srv/srv0start.cc
 	sync/sync0arr.cc
-	sync/sync0debug.cc
 	sync/sync0rw.cc
+	sync/sync0debug.cc
 	sync/sync0sync.cc
 	trx/trx0i_s.cc
 	trx/trx0purge.cc
@@ -500,7 +155,6 @@ SET(INNOBASE_SOURCES
 	trx/trx0trx.cc
 	trx/trx0undo.cc
 	usr/usr0sess.cc
-#	ut/ut0bh.cc
 	ut/ut0byte.cc
 	ut/ut0crc32.cc
 	ut/ut0dbg.cc
@@ -527,19 +181,42 @@ IF(WITH_INNODB)
   SET(WITH_INNOBASE_STORAGE_ENGINE TRUE)
 ENDIF()
 
-# On solaris, reduce symbol visibility, so loader does not mix
-# the same symbols from builtin innodb and from shared one.
-# Only required for old GCC (3.4.3) that does not support hidden visibility
-IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_COMPILER_IS_GNUCC 
-    AND NOT HAVE_VISIBILITY_HIDDEN)
-  SET(LINKER_SCRIPT "-Wl,-M${CMAKE_CURRENT_SOURCE_DIR}/plugin_exports")
-ELSE()
-  SET(LINKER_SCRIPT)
-ENDIF()
-
 MYSQL_ADD_PLUGIN(innobase ${INNOBASE_SOURCES} STORAGE_ENGINE
 #  MODULE_ONLY
 #  MODULE_OUTPUT_NAME ha_innodb
   DEFAULT RECOMPILE_FOR_EMBEDDED
   LINK_LIBRARIES ${ZLIB_LIBRARY} ${LINKER_SCRIPT})
 
+IF(WITH_INNOBASE_STORAGE_ENGINE)
+  ADD_DEPENDENCIES(innobase GenError)
+ENDIF()
+
+# Avoid generating Hardware Capabilities due to crc32 instructions
+IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_SYSTEM_PROCESSOR MATCHES "i386")
+  INCLUDE(${MYSQL_CMAKE_SCRIPT_DIR}/compile_flags.cmake)
+  MY_CHECK_CXX_COMPILER_FLAG("-Wa,-nH" HAVE_WA_NH)
+  IF(HAVE_WA_NH)
+    ADD_COMPILE_FLAGS(
+      ut/ut0crc32.cc
+      COMPILE_FLAGS "-Wa,-nH"
+    )
+  ENDIF()
+ENDIF()
+
+# A GCC bug causes crash when compiling these files on ARM64 with -O1+
+# Compile them with -O0 as a workaround.
+IF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
+  # Bug was fixed in GCC 5.2, so workaround only needed < 5.2
+  EXECUTE_PROCESS(COMMAND ${CMAKE_C_COMPILER} -dumpversion
+                  OUTPUT_VARIABLE GCC_VERSION)
+  IF(GCC_VERSION VERSION_LESS 5.2)
+    INCLUDE(${MYSQL_CMAKE_SCRIPT_DIR}/compile_flags.cmake)
+    ADD_COMPILE_FLAGS(
+      btr/btr0btr.cc
+      btr/btr0cur.cc
+      buf/buf0buf.cc
+      gis/gis0sea.cc
+      COMPILE_FLAGS "-O0"
+      )
+  ENDIF()
+ENDIF()
diff --git a/storage/innobase/api/api0api.cc b/storage/innobase/api/api0api.cc
index 1f04b1b..1b99dcf 100644
--- a/storage/innobase/api/api0api.cc
+++ b/storage/innobase/api/api0api.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2008, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2008, 2016, 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
@@ -1006,6 +1006,16 @@ ib_cursor_open_table(
 	return(err);
 }
 
+/** Check the table whether it contains virtual columns.
+ at param[in]	crsr	InnoDB Cursor
+ at return true if table contains virtual column else false. */
+ib_bool_t
+ib_is_virtual_table(
+	ib_crsr_t	crsr)
+{
+	return(crsr->prebuilt->table->n_v_cols > 0);
+}
+
 /********************************************************************//**
 Free a context struct for a table handle. */
 static
@@ -1262,12 +1272,14 @@ ib_insert_query_graph_create(
 		row = dtuple_create(heap, dict_table_get_n_cols(table));
 		dict_table_copy_types(row, table);
 
+		ut_ad(!dict_table_have_virtual_index(table));
+
 		ins_node_set_new_row(node->ins, row);
 
 		grph->ins = static_cast<que_fork_t*>(
 			que_node_get_parent(
 				pars_complete_graph_for_exec(node->ins, trx,
-							     heap)));
+							     heap, NULL)));
 
 		grph->ins->state = QUE_FORK_ACTIVE;
 	}
@@ -1376,9 +1388,12 @@ ib_update_vector_create(
 			row_create_update_node_for_mysql(table, heap));
 	}
 
+	ut_ad(!dict_table_have_virtual_index(table));
+
 	grph->upd = static_cast<que_fork_t*>(
 		que_node_get_parent(
-			pars_complete_graph_for_exec(node->upd, trx, heap)));
+			pars_complete_graph_for_exec(node->upd, trx,
+						     heap, NULL)));
 
 	grph->upd->state = QUE_FORK_ACTIVE;
 
@@ -3009,12 +3024,13 @@ ib_table_lock(
 	}
 
 	ut_a(ib_lck_mode <= static_cast<ib_lck_mode_t>(LOCK_NUM));
+	ut_ad(!dict_table_have_virtual_index(table));
 
 	heap = mem_heap_create(128);
 
 	q_proc.node.sel = sel_node_create(heap);
 
-	thr = pars_complete_graph_for_exec(q_proc.node.sel, trx, heap);
+	thr = pars_complete_graph_for_exec(q_proc.node.sel, trx, heap, NULL);
 
 	q_proc.grph.sel = static_cast<que_fork_t*>(que_node_get_parent(thr));
 	q_proc.grph.sel->state = QUE_FORK_ACTIVE;
diff --git a/storage/innobase/api/api0misc.cc b/storage/innobase/api/api0misc.cc
index c83eaed..3864e4b 100644
--- a/storage/innobase/api/api0misc.cc
+++ b/storage/innobase/api/api0misc.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2008, 2014, 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 the Free Software
@@ -45,69 +45,9 @@ ib_trx_lock_table_with_retry(
 	dict_table_t*	table,		/*!< in: table to lock */
 	enum lock_mode	mode)		/*!< in: LOCK_X or LOCK_S */
 {
-	que_thr_t*	thr;
-	dberr_t		err;
-	mem_heap_t*	heap;
-	sel_node_t*	node;
-
-	heap = mem_heap_create(512);
-
 	trx->op_info = "setting table lock";
 
-	node = sel_node_create(heap);
-	thr = pars_complete_graph_for_exec(node, trx, heap);
-	thr->graph->state = QUE_FORK_ACTIVE;
-
-	/* We use the select query graph as the dummy graph needed
-	in the lock module call */
-
-	thr = que_fork_get_first_thr(static_cast<que_fork_t*>(
-		que_node_get_parent(thr)));
-	que_thr_move_to_run_state_for_mysql(thr, trx);
-
-run_again:
-	thr->run_node = thr;
-	thr->prev_node = thr->common.parent;
-
-	err = lock_table(0, table, mode, thr);
-
-	trx->error_state = err;
-
-	if (UNIV_LIKELY(err == DB_SUCCESS)) {
-		que_thr_stop_for_mysql_no_error(thr, trx);
-	} else {
-		que_thr_stop_for_mysql(thr);
-
-		if (err != DB_QUE_THR_SUSPENDED) {
-			ibool	was_lock_wait;
-
-			was_lock_wait = ib_handle_errors(&err, trx, thr, NULL);
-
-			if (was_lock_wait) {
-				goto run_again;
-			}
-		} else {
-			que_thr_t*	run_thr;
-			que_node_t*	parent;
-
-			parent = que_node_get_parent(thr);
-			run_thr = que_fork_start_command(
-				static_cast<que_fork_t*>(parent));
-
-			ut_a(run_thr == thr);
-
-			/* There was a lock wait but the thread was not
-			in a ready to run or running state. */
-			trx->error_state = DB_LOCK_WAIT;
-
-			goto run_again;
-		}
-	}
-
-	que_graph_free(thr->graph);
-	trx->op_info = "";
-
-	return(err);
+	return(lock_table_for_trx(table, trx, mode));
 }
 /****************************************************************//**
 Handles user errors and lock waits detected by the database engine.
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc
index 36ec01d..2557882 100644
--- a/storage/innobase/btr/btr0btr.cc
+++ b/storage/innobase/btr/btr0btr.cc
@@ -338,8 +338,10 @@ btr_root_adjust_on_import(
 		} else {
 			/* Check that the table flags and the tablespace
 			flags match. */
-			ulint	flags = dict_tf_to_fsp_flags(table->flags,
-							     false);
+			ulint	flags = dict_tf_to_fsp_flags(
+				table->flags,
+				false,
+				dict_table_is_encrypted(table));
 			ulint	fsp_flags = fil_space_get_flags(table->space);
 			err = fsp_flags_are_equal(flags, fsp_flags)
 			      ? DB_SUCCESS : DB_CORRUPTION;
@@ -910,6 +912,7 @@ btr_page_get_father_node_ptr_func(
 
 	page_no = btr_cur_get_block(cursor)->page.id.page_no();
 	index = btr_cur_get_index(cursor);
+	ut_ad(!dict_index_is_spatial(index));
 
 	ut_ad(srv_read_only_mode
 	      || mtr_memo_contains_flagged(mtr, dict_index_get_lock(index),
@@ -923,44 +926,33 @@ btr_page_get_father_node_ptr_func(
 
 	user_rec = btr_cur_get_rec(cursor);
 	ut_a(page_rec_is_user_rec(user_rec));
-	tuple = dict_index_build_node_ptr(index, user_rec, 0, heap, level);
 
-	if (!dict_index_is_spatial(index)) {
-		dberr_t err = DB_SUCCESS;
-		if (dict_table_is_intrinsic(index->table)) {
-			err = btr_cur_search_to_nth_level_with_no_latch(
-				index, level + 1, tuple, PAGE_CUR_LE, cursor,
-				file, line, mtr);
-		} else {
-			err = btr_cur_search_to_nth_level(
-				index, level + 1, tuple,
-				PAGE_CUR_LE, latch_mode, cursor, 0,
-				file, line, mtr);
-		}
-
-		if (err != DB_SUCCESS) {
-			ib::warn() << " Error code: " << err
-				   << " btr_page_get_father_node_ptr_func "
-				   << " level: " << level + 1
-				   << " called from file: "
-				   << file << " line: " << line
-				   << " table: " << index->table->name
-				   << " index: " << index->name;
-		}
+	tuple = dict_index_build_node_ptr(index, user_rec, 0, heap, level);
+	dberr_t err = DB_SUCCESS;
+	
+	if (dict_table_is_intrinsic(index->table)) {
+		err = btr_cur_search_to_nth_level_with_no_latch(
+			index, level + 1, tuple, PAGE_CUR_LE, cursor,
+			file, line, mtr);
 	} else {
-		/* For R-tree, only latch mode from caller would be
-		BTR_CONT_MODIFY_TREE */
-		ut_ad(latch_mode == BTR_CONT_MODIFY_TREE);
+		err = btr_cur_search_to_nth_level(
+			index, level + 1, tuple,
+			PAGE_CUR_LE, latch_mode, cursor, 0,
+			file, line, mtr);
+	}
 
-		/* Try to avoid traverse from the root, and get the
-		father node from parent_path vector */
-		rtr_get_father_node(index, level + 1, tuple,
-				    NULL, cursor, page_no, mtr);
+	if (err != DB_SUCCESS) {
+		ib::warn() << " Error code: " << err
+			<< " btr_page_get_father_node_ptr_func "
+			<< " level: " << level + 1
+			<< " called from file: "
+			<< file << " line: " << line
+			<< " table: " << index->table->name
+			<< " index: " << index->name();
 	}
 
 	node_ptr = btr_cur_get_rec(cursor);
-	ut_ad(!page_rec_is_comp(node_ptr)
-	      || rec_get_status(node_ptr) == REC_STATUS_NODE_PTR);
+
 	offsets = rec_get_offsets(node_ptr, index, offsets,
 				  ULINT_UNDEFINED, &heap);
 
@@ -1106,7 +1098,7 @@ btr_free_root_invalidate(
 @param[in,out]	mtr		mini-transaction
 @return root block, to invoke btr_free_but_not_root() and btr_free_root()
 @retval NULL if the page is no longer a matching B-tree page */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
 buf_block_t*
 btr_free_root_check(
 	const page_id_t&	page_id,
@@ -1654,7 +1646,6 @@ IBUF_BITMAP_FREE is unaffected by reorganization.
 
 @retval true if the operation was successful
 @retval false if it is a compressed page, and recompression failed */
-UNIV_INTERN
 bool
 btr_page_reorganize_block(
 /*======================*/
@@ -1782,7 +1773,7 @@ the tuple. It is assumed that mtr contains an x-latch on the tree.
 NOTE that the operation of this function must always succeed,
 we cannot reverse it: therefore enough free disk space must be
 guaranteed to be available before this function is called.
- at return	inserted record or NULL if run out of space */
+ at return inserted record */
 rec_t*
 btr_root_raise_and_insert(
 /*======================*/
@@ -1848,7 +1839,7 @@ btr_root_raise_and_insert(
 
 	if (new_block == NULL && os_has_said_disk_full) {
 		return(NULL);
-        }
+	}
 
 	new_page = buf_block_get_frame(new_block);
 	new_page_zip = buf_block_get_page_zip(new_block);
@@ -2719,7 +2710,6 @@ released within this function! NOTE that the operation of this
 function must always succeed, we cannot reverse it: therefore enough
 free disk space (2 pages) must be guaranteed to be available before
 this function is called.
-
 NOTE: jonaso added support for calling function with tuple == NULL
 which cause it to only split a page.
 
@@ -2850,7 +2840,7 @@ btr_page_split_and_insert(
 
 	DBUG_EXECUTE_IF("disk_is_full",
 			os_has_said_disk_full = true;
-                        return(NULL););
+			return(NULL););
 
 	/* 2. Allocate a new page to the index */
 	new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
@@ -2858,7 +2848,7 @@ btr_page_split_and_insert(
 
 	if (new_block == NULL && os_has_said_disk_full) {
 		return(NULL);
-        }
+	}
 
 	new_page = buf_block_get_frame(new_block);
 	new_page_zip = buf_block_get_page_zip(new_block);
@@ -3164,7 +3154,6 @@ btr_page_split_and_insert(
 @param[in,out]	page		page to remove
 @param[in]	index		index tree
 @param[in,out]	mtr		mini-transaction */
-UNIV_INTERN
 void
 btr_level_list_remove_func(
 	ulint			space,
@@ -3369,8 +3358,15 @@ btr_lift_page_up(
 			* (REC_OFFS_HEADER_SIZE + 1 + 1 + index->n_fields));
 		buf_block_t*	b;
 
-		offsets = btr_page_get_father_block(offsets, heap, index,
-						    block, mtr, &cursor);
+		if (dict_index_is_spatial(index)) {
+			offsets = rtr_page_get_father_block(
+				NULL, heap, index, block, mtr,
+				NULL, &cursor);
+		} else {
+			offsets = btr_page_get_father_block(offsets, heap,
+							    index, block,
+							    mtr, &cursor);
+		}
 		father_block = btr_cur_get_block(&cursor);
 		father_page_zip = buf_block_get_page_zip(father_block);
 		father_page = buf_block_get_frame(father_block);
@@ -3386,9 +3382,17 @@ btr_lift_page_up(
 		     b->page.id.page_no() != root_page_no; ) {
 			ut_a(n_blocks < BTR_MAX_LEVELS);
 
-			offsets = btr_page_get_father_block(offsets, heap,
-							    index, b,
-							    mtr, &cursor);
+			if (dict_index_is_spatial(index)) {
+				offsets = rtr_page_get_father_block(
+					NULL, heap, index, b, mtr,
+					NULL, &cursor);
+			} else {
+				offsets = btr_page_get_father_block(offsets,
+								    heap,
+								    index, b,
+								    mtr,
+								    &cursor);
+			}
 
 			blocks[n_blocks++] = b = btr_cur_get_block(&cursor);
 		}
@@ -3460,6 +3464,13 @@ btr_lift_page_up(
 	}
 
 	if (!dict_table_is_locking_disabled(index->table)) {
+		/* Free predicate page locks on the block */
+		if (dict_index_is_spatial(index)) {
+			lock_mutex_enter();
+			lock_prdt_page_free_from_discard(
+				block, lock_sys->prdt_page_hash);
+			lock_mutex_exit();
+		}
 		lock_update_copy_and_discard(father_block, block);
 	}
 
@@ -3686,6 +3697,11 @@ btr_compress(
 				goto retry;
 			}
 
+			/* Set rtr_info for cursor2, since it is
+			necessary in recursive page merge. */
+			cursor2.rtr_info = cursor->rtr_info;
+			cursor2.tree_height = cursor->tree_height;
+
 			offsets2 = rec_get_offsets(
 				btr_cur_get_rec(&cursor2), index,
 				NULL, ULINT_UNDEFINED, &heap);
@@ -3744,6 +3760,8 @@ btr_compress(
 
 			/* No GAP lock needs to be worrying about */
 			lock_mutex_enter();
+			lock_prdt_page_free_from_discard(
+				block, lock_sys->prdt_page_hash);
 			lock_rec_free_all_from_discard_page(block);
 			lock_mutex_exit();
 		} else {
@@ -3781,6 +3799,11 @@ btr_compress(
 				merge_block, heap)) {
 				goto err_exit;
 			}
+
+			/* Set rtr_info for cursor2, since it is
+			necessary in recursive page merge. */
+			cursor2.rtr_info = cursor->rtr_info;
+			cursor2.tree_height = cursor->tree_height;
 		} else {
 			btr_page_get_father(index, merge_block, mtr, &cursor2);
 		}
@@ -3858,6 +3881,8 @@ btr_compress(
 		/* For rtree, we need to update father's mbr. */
 		if (dict_index_is_spatial(index)) {
 			ulint*	offsets2;
+			ulint	rec_info;
+
 			offsets2 = rec_get_offsets(
 				btr_cur_get_rec(&cursor2),
 				index, NULL, ULINT_UNDEFINED, &heap);
@@ -3866,12 +3891,34 @@ btr_compress(
 				btr_cur_get_rec(&cursor2), offsets2)
 				== right_page_no);
 
-			rtr_merge_and_update_mbr(&father_cursor,
-						 &cursor2,
-						 offsets, offsets2,
-						 merge_page, merge_block,
-						 block, index, mtr);
+			rec_info = rec_get_info_bits(
+				btr_cur_get_rec(&father_cursor),
+				rec_offs_comp(offsets));
+			if (rec_info & REC_INFO_MIN_REC_FLAG) {
+				/* When the father node ptr is minimal rec,
+				we will keep it and delete the node ptr of
+				merge page. */
+				rtr_merge_and_update_mbr(&father_cursor,
+							 &cursor2,
+							 offsets, offsets2,
+							 merge_page,
+							 merge_block,
+							 block, index, mtr);
+			} else {
+				/* Otherwise, we will keep the node ptr of
+				merge page and delete the father node ptr.
+				This is for keeping the rec order in upper
+				level. */
+				rtr_merge_and_update_mbr(&cursor2,
+							 &father_cursor,
+							 offsets2, offsets,
+							 merge_page,
+							 merge_block,
+							 block, index, mtr);
+			}
 			lock_mutex_enter();
+			lock_prdt_page_free_from_discard(
+				block, lock_sys->prdt_page_hash);
 			lock_rec_free_all_from_discard_page(block);
 			lock_mutex_exit();
 		} else {
@@ -4028,9 +4075,10 @@ btr_discard_only_page_on_level(
 		if (dict_index_is_spatial(index)) {
 			/* Check any concurrent search having this page */
 			rtr_check_discard_page(index, NULL, block);
+			rtr_page_get_father(index, block, mtr, NULL, &cursor);
+		} else {
+			btr_page_get_father(index, block, mtr, &cursor);
 		}
-
-		btr_page_get_father(index, block, mtr, &cursor);
 		father = btr_cur_get_block(&cursor);
 
 		if (!dict_table_is_locking_disabled(index->table)) {
@@ -4114,7 +4162,11 @@ btr_discard_page(
 	MONITOR_INC(MONITOR_INDEX_DISCARD);
 
 #ifdef UNIV_DEBUG
-	btr_page_get_father(index, block, mtr, &parent_cursor);
+	if (dict_index_is_spatial(index)) {
+		rtr_page_get_father(index, block, mtr, cursor, &parent_cursor);
+	} else {
+		btr_page_get_father(index, block, mtr, &parent_cursor);
+	}
 #endif
 
 	/* Decide the page which will inherit the locks */
@@ -4178,10 +4230,20 @@ btr_discard_page(
 		btr_set_min_rec_mark(node_ptr, mtr);
 	}
 
-	btr_node_ptr_delete(index, block, mtr);
+	if (dict_index_is_spatial(index)) {
+		btr_cur_t	father_cursor;
+
+		/* Since rtr_node_ptr_delete doesn't contain get father
+		node ptr, so, we need to get father node ptr first and then
+		delete it. */
+		rtr_page_get_father(index, block, mtr, cursor, &father_cursor);
+		rtr_node_ptr_delete(index, &father_cursor, block, mtr);
+	} else {
+		btr_node_ptr_delete(index, block, mtr);
+	}
 
 	/* Remove the page from the level list */
-	btr_level_list_remove(space, page_size, (page_t*)page, index, mtr);
+	btr_level_list_remove(space, page_size, page, index, mtr);
 
 #ifdef UNIV_ZIP_DEBUG
 	{
@@ -4377,8 +4439,14 @@ btr_check_node_ptr(
 	}
 
 	heap = mem_heap_create(256);
-	offsets = btr_page_get_father_block(NULL, heap, index, block, mtr,
-					    &cursor);
+
+	if (dict_index_is_spatial(index)) {
+		offsets = rtr_page_get_father_block(NULL, heap, index, block, mtr,
+						    NULL, &cursor);
+	} else {
+		offsets = btr_page_get_father_block(NULL, heap, index, block, mtr,
+						    &cursor);
+	}
 
 	if (page_is_leaf(page)) {
 
diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc
index 4a3de74..9ff3bc5 100644
--- a/storage/innobase/btr/btr0bulk.cc
+++ b/storage/innobase/btr/btr0bulk.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2014, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, 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
@@ -641,7 +641,7 @@ BtrBulk::pageSplit(
 
 	/* 1. Check if we have only one user record on the page. */
 	if (page_bulk->getRecNo() <= 1) {
-		return DB_TOO_BIG_RECORD;
+		return(DB_TOO_BIG_RECORD);
 	}
 
 	/* 2. create a new page. */
@@ -771,6 +771,7 @@ BtrBulk::insert(
 	ulint		level)
 {
 	bool		is_left_most = false;
+	dberr_t		err = DB_SUCCESS;
 
 	ut_ad(m_heap != NULL);
 
@@ -779,7 +780,7 @@ BtrBulk::insert(
 		PageBulk*	new_page_bulk
 			= UT_NEW_NOKEY(PageBulk(m_index, m_trx_id, FIL_NULL,
 						level, m_flush_observer));
-		dberr_t	err = new_page_bulk->init();
+		err = new_page_bulk->init();
 		if (err != DB_SUCCESS) {
 			return(err);
 		}
@@ -806,29 +807,37 @@ BtrBulk::insert(
 	ulint		n_ext = 0;
 	ulint		rec_size = rec_get_converted_size(m_index, tuple, n_ext);
 	big_rec_t*	big_rec = NULL;
+	rec_t*		rec = NULL;
+	ulint*		offsets = NULL;
 
 	if (page_bulk->needExt(tuple, rec_size)) {
 		/* The record is so big that we have to store some fields
 		externally on separate database pages */
 		big_rec = dtuple_convert_big_rec(m_index, 0, tuple, &n_ext);
 
-		if (UNIV_UNLIKELY(big_rec == NULL)) {
+		if (big_rec == NULL) {
 			return(DB_TOO_BIG_RECORD);
 		}
 
 		rec_size = rec_get_converted_size(m_index, tuple, n_ext);
 	}
 
+	if (page_bulk->getPageZip() != NULL
+	    && page_zip_is_too_big(m_index, tuple)) {
+		err = DB_TOO_BIG_RECORD;
+		goto func_exit;
+	}
+
 	if (!page_bulk->isSpaceAvailable(rec_size)) {
 		/* Create a sibling page_bulk. */
 		PageBulk*	sibling_page_bulk;
 		sibling_page_bulk = UT_NEW_NOKEY(PageBulk(m_index, m_trx_id,
 							  FIL_NULL, level,
 							  m_flush_observer));
-		dberr_t	err = sibling_page_bulk->init();
+		err = sibling_page_bulk->init();
 		if (err != DB_SUCCESS) {
 			UT_DELETE(sibling_page_bulk);
-			return(err);
+			goto func_exit;
 		}
 
 		/* Commit page bulk. */
@@ -836,7 +845,7 @@ BtrBulk::insert(
 		if (err != DB_SUCCESS) {
 			pageAbort(sibling_page_bulk);
 			UT_DELETE(sibling_page_bulk);
-			return(err);
+			goto func_exit;
 		}
 
 		/* Set new page bulk to page_bulks. */
@@ -850,7 +859,8 @@ BtrBulk::insert(
 		if (page_is_leaf(sibling_page_bulk->getPage())) {
 			/* Check whether trx is interrupted */
 			if (m_flush_observer->check_interrupted()) {
-				return(DB_INTERRUPTED);
+				err = DB_INTERRUPTED;
+				goto func_exit;
 			}
 
 			/* Wake up page cleaner to flush dirty pages. */
@@ -862,8 +872,6 @@ BtrBulk::insert(
 
 	}
 
-	rec_t*		rec;
-	ulint*		offsets = NULL;
 	/* Convert tuple to rec. */
         rec = rec_convert_dtuple_to_rec(static_cast<byte*>(mem_heap_alloc(
 		page_bulk->m_heap, rec_size)), m_index, tuple, n_ext);
@@ -873,8 +881,6 @@ BtrBulk::insert(
 	page_bulk->insert(rec, offsets);
 
 	if (big_rec != NULL) {
-		dberr_t		err;
-
 		ut_ad(dict_index_is_clust(m_index));
 		ut_ad(page_bulk->getLevel() == 0);
 		ut_ad(page_bulk == m_page_bulks->at(0));
@@ -893,13 +899,14 @@ BtrBulk::insert(
 			PageBulk*    page_bulk = m_page_bulks->at(level);
 			page_bulk->latch();
 		}
+	}
 
+func_exit:
+	if (big_rec != NULL) {
 		dtuple_convert_back_big_rec(m_index, tuple, big_rec);
-
-		return(err);
 	}
 
-	return(DB_SUCCESS);
+	return(err);
 }
 
 /** Btree bulk load finish. We commit the last page in each level
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index ab8ee1d..c1379be 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -723,7 +723,6 @@ If mode is PAGE_CUR_LE , cursor is left at the place where an insert of the
 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
 dberr_t
 btr_cur_search_to_nth_level(
 /*========================*/
@@ -1412,7 +1411,11 @@ btr_cur_search_to_nth_level(
 		level, the search becomes PAGE_CUR_LE */
 		if (page_mode == PAGE_CUR_RTREE_LOCATE
 		    && level == height) {
-			page_mode = PAGE_CUR_LE;
+			if (level == 0) {
+				page_mode = PAGE_CUR_LE;
+			} else {
+				page_mode = PAGE_CUR_RTREE_GET_FATHER;
+			}
 		}
 
 		if (page_mode == PAGE_CUR_RTREE_INSERT) {
@@ -1463,6 +1466,11 @@ btr_cur_search_to_nth_level(
 				ut_ad(0);
 			}
 		}
+
+		if (found && page_mode == PAGE_CUR_RTREE_GET_FATHER) {
+			cursor->low_match =
+				DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1;
+		}
 	} else if (height == 0 && btr_search_enabled
 		   && !dict_index_is_spatial(index)) {
 		/* The adaptive hash index is only used when searching
@@ -2102,7 +2110,7 @@ btr_cur_search_to_nth_level_with_no_latch(
 		ut_ad(n_blocks < BTR_MAX_LEVELS);
 
 		block = buf_page_get_gen(page_id, page_size, rw_latch, NULL,
-					 buf_mode, file, line, mtr, &err, mark_dirty);
+			buf_mode, file, line, mtr, &err, mark_dirty);
 
 		if (err != DB_SUCCESS) {
 			if (err == DB_DECRYPTION_FAILED) {
@@ -2115,7 +2123,7 @@ btr_cur_search_to_nth_level_with_no_latch(
 				index->table->is_encrypted = true;
 			}
 
-			return (err);
+			DBUG_RETURN(err);
 		}
 
 		page = buf_block_get_frame(block);
@@ -2171,7 +2179,7 @@ btr_cur_search_to_nth_level_with_no_latch(
 		mem_heap_free(heap);
 	}
 
-	return err;
+	DBUG_RETURN(err);
 }
 
 /*****************************************************************//**
@@ -2578,7 +2586,6 @@ btr_cur_open_at_index_side_with_no_latch_func(
 	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
 	ulint*		offsets		= offsets_;
 	dberr_t		err = DB_SUCCESS;
-
 	rec_offs_init(offsets_);
 
 	ut_ad(level != ULINT_UNDEFINED);
@@ -2599,7 +2606,7 @@ btr_cur_open_at_index_side_with_no_latch_func(
 		ut_ad(n_blocks < BTR_MAX_LEVELS);
 
 		block = buf_page_get_gen(page_id, page_size, rw_latch, NULL,
-					 BUF_GET, file, line, mtr, &err);
+			BUF_GET, file, line, mtr, &err);
 
 		if (err != DB_SUCCESS) {
 			if (err == DB_DECRYPTION_FAILED) {
@@ -2665,7 +2672,7 @@ btr_cur_open_at_index_side_with_no_latch_func(
 		mem_heap_free(heap);
 	}
 
-	return (err);
+	return(err);
 }
 
 /**********************************************************************//**
@@ -2759,6 +2766,7 @@ btr_cur_open_at_rnd_pos_func(
 	page_id_t		page_id(dict_index_get_space(index),
 					dict_index_get_page(index));
 	const page_size_t&	page_size = dict_table_page_size(index->table);
+	dberr_t			err = DB_SUCCESS;
 
 	if (root_leaf_rw_latch == RW_X_LATCH) {
 		node_ptr_max_size = dict_index_node_ptr_max_size(index);
@@ -2769,7 +2777,6 @@ btr_cur_open_at_rnd_pos_func(
 	for (;;) {
 		buf_block_t*	block;
 		page_t*		page;
-		dberr_t		err=DB_SUCCESS;
 		ulint		rw_latch;
 
 		ut_ad(n_blocks < BTR_MAX_LEVELS);
@@ -2783,10 +2790,9 @@ btr_cur_open_at_rnd_pos_func(
 
 		tree_savepoints[n_blocks] = mtr_set_savepoint(mtr);
 		block = buf_page_get_gen(page_id, page_size, rw_latch, NULL,
-					 BUF_GET, file, line, mtr, &err);
+			BUF_GET, file, line, mtr, &err);
 		tree_blocks[n_blocks] = block;
 
-
 		if (err != DB_SUCCESS) {
 			if (err == DB_DECRYPTION_FAILED) {
 				ib_push_warning((void *)NULL,
@@ -3222,46 +3228,12 @@ btr_cur_optimistic_insert(
 		rec_size = rec_get_converted_size(index, entry, n_ext);
 	}
 
-	if (page_size.is_compressed()) {
-		/* Estimate the free space of an empty compressed page.
-		Subtract one byte for the encoded heap_no in the
-		modification log. */
-		ulint	free_space_zip = page_zip_empty_size(
-			cursor->index->n_fields, page_size.physical());
-		ulint	n_uniq = dict_index_get_n_unique_in_tree(index);
-
-		ut_ad(dict_table_is_comp(index->table));
-
-		if (free_space_zip == 0) {
-too_big:
-			if (big_rec_vec) {
-				dtuple_convert_back_big_rec(
-					index, entry, big_rec_vec);
-			}
-
-			return(DB_TOO_BIG_RECORD);
+	if (page_size.is_compressed() && page_zip_is_too_big(index, entry)) {
+		if (big_rec_vec != NULL) {
+			dtuple_convert_back_big_rec(index, entry, big_rec_vec);
 		}
 
-		/* Subtract one byte for the encoded heap_no in the
-		modification log. */
-		free_space_zip--;
-
-		/* There should be enough room for two node pointer
-		records on an empty non-leaf page.  This prevents
-		infinite page splits. */
-
-		if (entry->n_fields >= n_uniq
-		    && (REC_NODE_PTR_SIZE
-			+ rec_get_converted_size_comp_prefix(
-				index, entry->fields, n_uniq, NULL)
-			/* On a compressed page, there is
-			a two-byte entry in the dense
-			page directory for every record.
-			But there is no record header. */
-			- (REC_N_NEW_EXTRA_BYTES - 2)
-			> free_space_zip / 2)) {
-			goto too_big;
-		}
+		return(DB_TOO_BIG_RECORD);
 	}
 
 	LIMIT_OPTIMISTIC_INSERT_DEBUG(page_get_n_recs(page),
@@ -3323,12 +3295,12 @@ btr_cur_optimistic_insert(
 #ifdef UNIV_DEBUG
 	{
 		rec_printer p(entry);
-		DBUG_PRINT("ib_cur", ("insert %s (%llu) by %lu %s",
-				index->name(), index->id,
-				thr != NULL
-				? trx_get_id_for_print(thr_get_trx(thr))
-				: 0,
-				p.str().c_str()));
+		DBUG_PRINT("ib_cur", ("insert %s (" IB_ID_FMT ") by " IB_ID_FMT " %s",
+			      index->name(), index->id,
+			      thr != NULL
+			      ? trx_get_id_for_print(thr_get_trx(thr))
+			      : 0,
+			      p.str().c_str()));
 	}
 #endif
 
@@ -3350,7 +3322,6 @@ btr_cur_optimistic_insert(
 			if specified */
 			err = btr_cur_ins_lock_and_undo(flags, cursor, entry,
 							thr, mtr, &inherit);
-
 			if (err != DB_SUCCESS) {
 				goto fail_err;
 			}
@@ -3592,6 +3563,7 @@ btr_cur_pessimistic_insert(
 					btr_cur_get_page_zip(cursor),
 					thr_get_trx(thr)->id, mtr);
 			}
+
 			if (!page_rec_is_infimum(btr_cur_get_rec(cursor))
 			    || btr_page_get_prev(
 				buf_block_get_frame(
@@ -3601,18 +3573,6 @@ btr_cur_pessimistic_insert(
 				lock_update_insert() always. */
 				inherit = TRUE;
 			}
-
-		buf_block_t* block = btr_cur_get_block(cursor);
-		buf_frame_t* frame = NULL;
-
-		if (block) {
-			frame = buf_block_get_frame(block);
-		}
-		/* split and inserted need to call
-		lock_update_insert() always. */
-		if (frame &&  btr_page_get_prev(frame, mtr) == FIL_NULL) {
-			inherit = TRUE;
-		}
 		}
 	}
 
@@ -3640,7 +3600,7 @@ btr_cur_pessimistic_insert(
 /*************************************************************//**
 For an update, checks the locks and does the undo logging.
 @return DB_SUCCESS, DB_WAIT_LOCK, or error number */
-UNIV_INLINE MY_ATTRIBUTE((warn_unused_result, nonnull(2,3,6,7)))
+UNIV_INLINE MY_ATTRIBUTE((warn_unused_result))
 dberr_t
 btr_cur_upd_lock_and_undo(
 /*======================*/
@@ -3978,8 +3938,8 @@ btr_cur_update_in_place(
 #ifdef UNIV_DEBUG
 	{
 		rec_printer p(rec, offsets);
-		DBUG_PRINT("ib_cur", ("update-in-place %s (%llu) by %lu: %s",
-				index->name(), index->id, trx_id,
+		DBUG_PRINT("ib_cur", ("update-in-place %s (" IB_ID_FMT ") by "IB_ID_FMT ": %s",
+				index->name(), (ulint)index->id, trx_id,
 				p.str().c_str()));
 	}
 #endif
@@ -4186,8 +4146,8 @@ btr_cur_optimistic_update(
 #ifdef UNIV_DEBUG
 	{
 		rec_printer p(rec, *offsets);
-		DBUG_PRINT("ib_cur", ("update %s (%llu) by %lu: %s",
-			index->name(), index->id, trx_id,
+		DBUG_PRINT("ib_cur", ("update %s (" IB_ID_FMT ") by " IB_ID_FMT ": %s",
+				index->name(), (ulint)index->id, trx_id,
 			p.str().c_str()));
 	}
 #endif
@@ -5026,8 +4986,8 @@ btr_cur_del_mark_set_clust_rec(
 #ifdef UNIV_DEBUG
 	{
 		rec_printer p(rec, offsets);
-		DBUG_PRINT("ib_cur", ("delete-mark clust %s (%llu) by %lu: %s",
-				index->table_name, index->id,
+		DBUG_PRINT("ib_cur", ("delete-mark clust %s (" IB_ID_FMT ") by " IB_ID_FMT ": %s",
+				index->table_name, (ulint)index->id,
 				trx_get_id_for_print(trx),
 				p.str().c_str()));
 	}
@@ -5154,7 +5114,7 @@ btr_cur_del_mark_set_sec_rec(
 	      == dict_table_is_comp(cursor->index->table));
 
 	DBUG_PRINT("ib_cur", ("delete-mark=%u sec %u:%u:%u in %s("
-			      UINT32PF ") by " TRX_ID_FMT,
+			      IB_ID_FMT ") by " TRX_ID_FMT,
 			      unsigned(val),
 			      block->page.id.space(), block->page.id.page_no(),
 			      unsigned(page_rec_get_heap_no(rec)),
@@ -5231,10 +5191,15 @@ btr_cur_compress_if_useful(
 
 	if (dict_index_is_spatial(cursor->index)) {
 		const page_t*   page = btr_cur_get_page(cursor);
+		const trx_t*	trx = NULL;
+
+		if (cursor->rtr_info->thr != NULL) {
+			trx = thr_get_trx(cursor->rtr_info->thr);
+		}
 
 		/* Check whether page lock prevents the compression */
-		if (!lock_test_prdt_page_lock(
-			page_get_space_id(page), page_get_page_no(page))) {
+		if (!lock_test_prdt_page_lock(trx, page_get_space_id(page),
+					      page_get_page_no(page))) {
 			return(false);
 		}
 	}
@@ -5840,7 +5805,6 @@ btr_estimate_n_rows_in_range_low(
 
 	table_n_rows = dict_table_get_n_rows(index->table);
 
-	mtr_start(&mtr);
 	/* Below we dive to the two records specified by tuple1 and tuple2 and
 	we remember the entire dive paths from the tree root. The place where
 	the tuple1 path ends on the leaf level we call "left border" of our
@@ -5850,6 +5814,7 @@ btr_estimate_n_rows_in_range_low(
 	example if "5 < x AND x <= 10" then we should not include the left
 	boundary, but should include the right one. */
 
+	mtr_start(&mtr);
 
 	cursor.path_arr = path1;
 
@@ -6910,6 +6875,8 @@ struct btr_blob_log_check_t {
 
 		log_free_check();
 
+		DEBUG_SYNC_C("blob_write_middle_after_check");
+
 		const mtr_log_t log_mode = m_mtr->get_log_mode();
 		m_mtr->start();
 		m_mtr->set_log_mode(log_mode);
@@ -7065,10 +7032,7 @@ btr_store_big_rec_extern_fields(
 	}
 #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
 
-	/* Calculate the total number of pages for blob data */
-	ulint	total_blob_pages = 0;
 	const page_size_t	page_size(dict_table_page_size(index->table));
-	const ulint pages_in_extent = dict_table_extent_size(index->table);
 
 	/* Space available in compressed page to carry blob data */
 	const ulint	payload_size_zip = page_size.physical()
@@ -7078,55 +7042,6 @@ btr_store_big_rec_extern_fields(
 	const ulint	payload_size = page_size.physical()
 		- FIL_PAGE_DATA - BTR_BLOB_HDR_SIZE - FIL_PAGE_DATA_END;
 
-	if (page_size.is_compressed()) {
-		for (ulint i = 0; i < big_rec_vec->n_fields; i++) {
-			total_blob_pages
-				+= static_cast<ulint>
-				   (compressBound(static_cast<uLong>
-						  (big_rec_vec->fields[i].len))
-				    + payload_size_zip - 1)
-				   / payload_size_zip;
-		}
-	} else {
-		for (ulint i = 0; i < big_rec_vec->n_fields; i++) {
-			total_blob_pages += (big_rec_vec->fields[i].len
-					     + payload_size - 1)
-				/ payload_size;
-		}
-	}
-
-	const ulint	n_extents = (total_blob_pages + pages_in_extent - 1)
-		/ pages_in_extent;
-	ulint	n_reserved = 0;
-#ifdef UNIV_DEBUG
-	ulint	n_used = 0;	/* number of pages used */
-#endif /* UNIV_DEBUG */
-
-	if (op == BTR_STORE_INSERT_BULK) {
-		mtr_t	alloc_mtr;
-
-		mtr_start(&alloc_mtr);
-		alloc_mtr.set_named_space(index->space);
-
-		if (!fsp_reserve_free_extents(&n_reserved, space_id, n_extents,
-					      FSP_BLOB, &alloc_mtr)) {
-			mtr_commit(&alloc_mtr);
-			error = DB_OUT_OF_FILE_SPACE;
-			goto func_exit;
-		}
-
-		mtr_commit(&alloc_mtr);
-	} else {
-		if (!fsp_reserve_free_extents(&n_reserved, space_id, n_extents,
-					      FSP_BLOB, btr_mtr)) {
-			error = DB_OUT_OF_FILE_SPACE;
-			goto func_exit;
-		}
-	}
-
-	ut_ad(n_reserved > 0);
-	ut_ad(n_reserved == n_extents);
-
 	/* We have to create a file segment to the tablespace
 	for each field and put the pointer to the field in rec */
 
@@ -7160,6 +7075,7 @@ btr_store_big_rec_extern_fields(
 			buf_block_t*	block;
 			page_t*		page;
 			const ulint	commit_freq = 4;
+			ulint		r_extents;
 
 			ut_ad(page_align(field_ref) == page_align(rec));
 
@@ -7188,23 +7104,35 @@ btr_store_big_rec_extern_fields(
 				hint_page_no = prev_page_no + 1;
 			}
 
+			mtr_t	*alloc_mtr;
+
 			if (op == BTR_STORE_INSERT_BULK) {
-				mtr_t	alloc_mtr;
+				mtr_start(&mtr_bulk);
+				mtr_bulk.set_spaces(mtr);
+				alloc_mtr = &mtr_bulk;
+			} else {
+				alloc_mtr = &mtr;
+			}
+
+			if (!fsp_reserve_free_extents(&r_extents, space_id, 1,
+						      FSP_BLOB, alloc_mtr,
+						      1)) {
 
-				mtr_start(&alloc_mtr);
-				alloc_mtr.set_named_space(index->space);
+				mtr_commit(alloc_mtr);
+				error = DB_OUT_OF_FILE_SPACE;
+				goto func_exit;
+			}
 
-				block = btr_page_alloc(index, hint_page_no,
-					FSP_NO_DIR, 0, &alloc_mtr, &mtr);
-				mtr_commit(&alloc_mtr);
+			block = btr_page_alloc(index, hint_page_no, FSP_NO_DIR,
+					       0, alloc_mtr, &mtr);
 
-			} else {
-				block = btr_page_alloc(index, hint_page_no,
-					FSP_NO_DIR, 0, &mtr, &mtr);
+			alloc_mtr->release_free_extents(r_extents);
+
+			if (op == BTR_STORE_INSERT_BULK) {
+				mtr_commit(&mtr_bulk);
 			}
 
 			ut_a(block != NULL);
-			ut_ad(++n_used <= (n_reserved * pages_in_extent));
 
 			page_no = block->page.id.page_no();
 			page = buf_block_get_frame(block);
@@ -7443,13 +7371,6 @@ btr_store_big_rec_extern_fields(
 		rec_offs_make_nth_extern(offsets, field_no);
 	}
 
-	/* Verify that the number of extents used is the same as the number
-	of extents reserved. */
-	ut_ad(page_zip != NULL
-	      || ((n_used + pages_in_extent - 1) / pages_in_extent
-		  == n_reserved));
-	ut_ad((n_used + pages_in_extent - 1) / pages_in_extent <= n_reserved);
-
 func_exit:
 	if (page_zip) {
 		deflateEnd(&c_stream);
@@ -7459,8 +7380,6 @@ btr_store_big_rec_extern_fields(
 		mem_heap_free(heap);
 	}
 
-	fil_space_release_free_extents(space_id, n_reserved);
-
 #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
 	/* All pointers to externally stored columns in the record
 	must be valid. */
@@ -7545,7 +7464,7 @@ btr_free_externally_stored_field(
 	ulint		i,		/*!< in: field number of field_ref;
 					ignored if rec == NULL */
 	bool		rollback,	/*!< in: performing rollback? */
-	mtr_t*		local_mtr MY_ATTRIBUTE((unused))) /*!< in: mtr
+	mtr_t*		local_mtr)	/*!< in: mtr
 					containing the latch to data an an
 					X-latch to the index tree */
 {
@@ -7659,7 +7578,7 @@ btr_free_externally_stored_field(
 			next_page_no = mach_read_from_4(page + FIL_PAGE_NEXT);
 
 			btr_page_free_low(index, ext_block, 0,
-					  true, &mtr);
+				true, &mtr);
 
 			if (page_zip != NULL) {
 				mach_write_to_4(field_ref + BTR_EXTERN_PAGE_NO,
@@ -7686,8 +7605,11 @@ btr_free_externally_stored_field(
 				page + FIL_PAGE_DATA
 				+ BTR_BLOB_HDR_NEXT_PAGE_NO);
 
+			/* We must supply the page level (= 0) as an argument
+			because we did not store it on the page (we save the
+			space overhead from an index page header. */
 			btr_page_free_low(index, ext_block, 0,
-					  true, &mtr);
+				true, &mtr);
 
 			mlog_write_ulint(field_ref + BTR_EXTERN_PAGE_NO,
 					 next_page_no,
diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc
index bacc3a4..52ed728 100644
--- a/storage/innobase/btr/btr0defragment.cc
+++ b/storage/innobase/btr/btr0defragment.cc
@@ -1,7 +1,7 @@
 /*****************************************************************************
 
 Copyright (C) 2013, 2014 Facebook, Inc. All Rights Reserved.
-Copyright (C) 2014, 2015, MariaDB Corporation. All Rights Reserved.
+Copyright (C) 2014, 2016, 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
@@ -33,6 +33,7 @@ Modified 30/07/2014 Jan Lindström jan.lindstrom at mariadb.com
 #include "btr0pcur.h"
 #include "dict0stats.h"
 #include "dict0stats_bg.h"
+#include "dict0defrag_bg.h"
 #include "ibuf0ibuf.h"
 #include "lock0lock.h"
 #include "srv0start.h"
@@ -153,7 +154,7 @@ btr_defragment_init()
 {
 	srv_defragment_interval = ut_microseconds_to_timer(
 		(ulonglong) (1000000.0 / srv_defragment_frequency));
-	mutex_create(LATCH_ID_DEFRAGMENT_MUTEX, &btr_defragment_mutex);
+	mutex_create(LATCH_ID_BTR_DEFRAGMENT_MUTEX, &btr_defragment_mutex);
 	os_thread_create(btr_defragment_thread, NULL, NULL);
 }
 
@@ -818,16 +819,32 @@ DECLARE_THREAD(btr_defragment_thread)(
 			/* Update the last_processed time of this index. */
 			item->last_processed = now;
 		} else {
+			dberr_t err = DB_SUCCESS;
 			mtr_commit(&mtr);
 			/* Reaching the end of the index. */
 			dict_stats_empty_defrag_stats(index);
-			dict_stats_save_defrag_stats(index);
-			dict_stats_save_defrag_summary(index);
+			err = dict_stats_save_defrag_stats(index);
+			if (err != DB_SUCCESS) {
+				ib::error() << "Saving defragmentation stats for table "
+					    << index->table->name.m_name
+					    << " index " << index->name()
+					    << " failed with error " << err;
+			} else {
+				err = dict_stats_save_defrag_summary(index);
+
+				if (err != DB_SUCCESS) {
+					ib::error() << "Saving defragmentation summary for table "
+					    << index->table->name.m_name
+					    << " index " << index->name()
+					    << " failed with error " << err;
+				}
+			}
+
 			btr_defragment_remove_item(item);
 		}
 	}
 	btr_defragment_shutdown();
-	os_thread_exit(NULL);
+	os_thread_exit();
 	OS_THREAD_DUMMY_RETURN;
 }
 
diff --git a/storage/innobase/btr/btr0scrub.cc b/storage/innobase/btr/btr0scrub.cc
index 88ec4f0..8ed0117 100644
--- a/storage/innobase/btr/btr0scrub.cc
+++ b/storage/innobase/btr/btr0scrub.cc
@@ -412,7 +412,6 @@ btr_pessimistic_scrub(
 	}
 
 	/* read block variables */
-	const ulint space_id = mach_read_from_4(page + FIL_PAGE_SPACE_ID);
 	const ulint page_no =  mach_read_from_4(page + FIL_PAGE_OFFSET);
 	const page_id_t page_id(dict_index_get_space(index), page_no);
 	const ulint left_page_no = btr_page_get_prev(page, mtr);
@@ -434,7 +433,7 @@ btr_pessimistic_scrub(
 		*/
 		mtr->release_block_at_savepoint(scrub_data->savepoint, block);
 
-		buf_block_t* get_block = btr_block_get(
+		buf_block_t* get_block __attribute__((unused)) = btr_block_get(
 			lpage_id, page_size,
 			RW_X_LATCH, index, mtr);
 
@@ -455,7 +454,7 @@ btr_pessimistic_scrub(
 	}
 
 	if (right_page_no != FIL_NULL) {
-		buf_block_t* get_block = btr_block_get(
+		buf_block_t* get_block __attribute__((unused))= btr_block_get(
 			rpage_id, page_size,
 			RW_X_LATCH, index, mtr);
 	}
diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc
index 60104b6..4489775 100644
--- a/storage/innobase/btr/btr0sea.cc
+++ b/storage/innobase/btr/btr0sea.cc
@@ -52,8 +52,13 @@ char		btr_search_enabled	= true;
 /** Number of adaptive hash index partition. */
 ulong		btr_ahi_parts		= 8;
 
+#ifdef UNIV_SEARCH_PERF_STAT
+/** Number of successful adaptive hash index lookups */
 ulint		btr_search_n_succ	= 0;
+/** Number of failed adaptive hash index lookups */
 ulint		btr_search_n_hash_fail	= 0;
+#endif /* UNIV_SEARCH_PERF_STAT */
+
 /** padding to prevent other memory update
 hotspots from residing on the same memory
 cache line as btr_search_latches */
@@ -87,7 +92,7 @@ before hash index building is started */
 @param[in]	n_fields	number of complete fields
 @param[in]	n_bytes		number of bytes in an incomplete last field
 @return	number of complete or incomplete fields */
-inline __attribute__((warn_unused_result))
+inline MY_ATTRIBUTE((warn_unused_result))
 ulint
 btr_search_get_n_fields(
 	ulint	n_fields,
@@ -99,7 +104,7 @@ btr_search_get_n_fields(
 /** Determine the number of accessed key fields.
 @param[in]	cursor		b-tree cursor
 @return	number of complete or incomplete fields */
-inline __attribute__((warn_unused_result))
+inline MY_ATTRIBUTE((warn_unused_result))
 ulint
 btr_search_get_n_fields(
 	const btr_cur_t*	cursor)
@@ -561,7 +566,7 @@ ibool
 btr_search_update_block_hash_info(
 	btr_search_t*		info,
 	buf_block_t*		block,
-	const btr_cur_t*	cursor MY_ATTRIBUTE((unused)))
+	const btr_cur_t*	cursor)
 {
 	ut_ad(!rw_lock_own(btr_get_search_latch(cursor->index), RW_LOCK_S));
 	ut_ad(!rw_lock_own(btr_get_search_latch(cursor->index), RW_LOCK_X));
@@ -728,6 +733,10 @@ btr_search_info_update_slow(
 	if (cursor->flag == BTR_CUR_HASH_FAIL) {
 		/* Update the hash node reference, if appropriate */
 
+#ifdef UNIV_SEARCH_PERF_STAT
+		btr_search_n_hash_fail++;
+#endif /* UNIV_SEARCH_PERF_STAT */
+
 		btr_search_x_lock(cursor->index);
 
 		btr_search_update_hash_ref(info, block, cursor);
@@ -1011,7 +1020,7 @@ btr_search_guess_on_hash(
 		return(FALSE);
 	}
 
-	buf_block_t*	block = buf_block_align(rec);
+	buf_block_t*	block = buf_block_from_ahi(rec);
 
 	if (!has_search_latch) {
 
@@ -1114,6 +1123,9 @@ btr_search_guess_on_hash(
 #endif
 	info->last_hash_succ = TRUE;
 
+#ifdef UNIV_SEARCH_PERF_STAT
+	btr_search_n_succ++;
+#endif
 	if (!has_search_latch && buf_page_peek_if_too_old(&block->page)) {
 
 		buf_page_make_young(&block->page);
@@ -1121,7 +1133,6 @@ btr_search_guess_on_hash(
 
 	/* Increment the page get statistics though we did not really
 	fix the page: for user info only */
-
 	{
 		buf_pool_t*	buf_pool = buf_pool_from_bpage(&block->page);
 
@@ -1181,7 +1192,8 @@ btr_search_drop_page_hash_index(buf_block_t* block)
 	const index_id_t	index_id
 		= btr_page_get_index_id(block->frame);
 	const ulint		ahi_slot
-		= ut_fold_ulint_pair(index_id, block->page.id.space())
+		= ut_fold_ulint_pair(static_cast<ulint>(index_id),
+				     static_cast<ulint>(block->page.id.space()))
 		% btr_ahi_parts;
 	latch = btr_search_latches[ahi_slot];
 
@@ -2006,7 +2018,7 @@ btr_search_hash_table_validate(ulint hash_table_id)
 
 		for (; node != NULL; node = node->next) {
 			const buf_block_t*	block
-				= buf_block_align((byte*) node->data);
+				= buf_block_from_ahi((byte*) node->data);
 			const buf_block_t*	hash_block;
 			buf_pool_t*		buf_pool;
 			index_id_t		page_index_id;
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 04260df..bc4efa4 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -72,14 +72,9 @@ Created 11/5/1995 Heikki Tuuri
 #include "sync0sync.h"
 #include "buf0dump.h"
 #include "ut0new.h"
-
 #include <new>
 #include <map>
 #include <sstream>
-#ifdef HAVE_LIBNUMA
-#include <numa.h>
-#include <numaif.h>
-#endif // HAVE_LIBNUMA
 #ifndef UNIV_INNOCHECKSUM
 #include "fil0pagecompress.h"
 #include "fsp0pagecompress.h"
@@ -92,6 +87,48 @@ Created 11/5/1995 Heikki Tuuri
 #include "lzo/lzo1x.h"
 #endif
 
+#if defined(HAVE_LIBNUMA) && defined(WITH_NUMA)
+#include <numa.h>
+#include <numaif.h>
+struct set_numa_interleave_t
+{
+	set_numa_interleave_t()
+	{
+		if (srv_numa_interleave) {
+
+			ib::info() << "Setting NUMA memory policy to"
+				" MPOL_INTERLEAVE";
+			if (set_mempolicy(MPOL_INTERLEAVE,
+					  numa_all_nodes_ptr->maskp,
+					  numa_all_nodes_ptr->size) != 0) {
+
+				ib::warn() << "Failed to set NUMA memory"
+					" policy to MPOL_INTERLEAVE: "
+					<< strerror(errno);
+			}
+		}
+	}
+
+	~set_numa_interleave_t()
+	{
+		if (srv_numa_interleave) {
+
+			ib::info() << "Setting NUMA memory policy to"
+				" MPOL_DEFAULT";
+			if (set_mempolicy(MPOL_DEFAULT, NULL, 0) != 0) {
+				ib::warn() << "Failed to set NUMA memory"
+					" policy to MPOL_DEFAULT: "
+					<< strerror(errno);
+			}
+		}
+	}
+};
+
+#define NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE set_numa_interleave_t scoped_numa
+#else
+#define NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE
+#endif /* HAVE_LIBNUMA && WITH_NUMA */
+
 /*
 		IMPLEMENTATION OF THE BUFFER POOL
 		=================================
@@ -323,10 +360,6 @@ The map pointed by this should not be updated */
 static buf_pool_chunk_map_t*	buf_chunk_map_ref = NULL;
 
 #ifdef UNIV_DEBUG
-/** Protect reference for buf_chunk_map_ref from deleting map,
-because the reference can be caused by debug assertion code. */
-static rw_lock_t*	buf_chunk_map_latch;
-
 /** Disable resizing buffer pool to make assertion code not expensive. */
 my_bool			buf_disable_resize_buffer_pool_debug = TRUE;
 #endif /* UNIV_DEBUG */
@@ -569,29 +602,31 @@ buf_page_is_zeroes(
 }
 
 /** Checks if the page is in crc32 checksum format.
- at param[in]	read_buf	database page
- at param[in]	checksum_field1	new checksum field
- at param[in]	checksum_field2	old checksum field
- at param[in]	page_no		page number of given read_buf
- at param[in]	is_log_enabled	true if log option is enabled
- at param[in]	log_file	file pointer to log_file
- at param[in]	curr_algo	current checksum algorithm
+ at param[in]	read_buf		database page
+ at param[in]	checksum_field1		new checksum field
+ at param[in]	checksum_field2		old checksum field
+ at param[in]	page_no			page number of given read_buf
+ at param[in]	is_log_enabled		true if log option is enabled
+ at param[in]	log_file		file pointer to log_file
+ at param[in]	curr_algo		current checksum algorithm
+ at param[in]	use_legacy_big_endian   use legacy big endian algorithm
 @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
+	ulint				checksum_field2,
 #ifdef UNIV_INNOCHECKSUM
-	,uintmax_t			page_no,
+	uintmax_t			page_no,
 	bool				is_log_enabled,
 	FILE*				log_file,
-	const srv_checksum_algorithm_t	curr_algo
+	const srv_checksum_algorithm_t	curr_algo,
 #endif /* UNIV_INNOCHECKSUM */
-	)
+	bool				use_legacy_big_endian)
 {
-	const uint32_t	crc32 = buf_calc_page_crc32(read_buf);
+	const uint32_t	crc32 = buf_calc_page_crc32(read_buf,
+						    use_legacy_big_endian);
 
 #ifdef UNIV_INNOCHECKSUM
 	if (is_log_enabled
@@ -740,6 +775,7 @@ buf_page_is_checksum_valid_none(
 	}
 #endif /* UNIV_INNOCHECKSUM */
 
+
 	return(checksum_field1 == checksum_field2
 	       && checksum_field1 == BUF_NO_CHECKSUM_MAGIC);
 }
@@ -896,16 +932,18 @@ buf_page_is_corrupted(
 	const srv_checksum_algorithm_t	curr_algo =
 		static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
 
+	bool	legacy_checksum_checked = false;
+
 	switch (curr_algo) {
 	case SRV_CHECKSUM_ALGORITHM_CRC32:
 	case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
 
 		if (buf_page_is_checksum_valid_crc32(read_buf,
-			checksum_field1, checksum_field2
+			checksum_field1, checksum_field2,
 #ifdef UNIV_INNOCHECKSUM
-			, page_no, is_log_enabled, log_file, curr_algo
+			page_no, is_log_enabled, log_file, curr_algo,
 #endif /* UNIV_INNOCHECKSUM */
-			)) {
+			false)) {
 			return(FALSE);
 		}
 
@@ -928,13 +966,13 @@ buf_page_is_corrupted(
 			if (is_log_enabled) {
 
 				fprintf(log_file, "page::%lu;"
-					" old style: calculated = %lu;"
-					" recorded = %lu\n", page_no,
+					" old style: calculated = " ULINTPF ";"
+					" recorded = " ULINTPF "\n", page_no,
 					buf_calc_page_old_checksum(read_buf),
 					checksum_field2);
 				fprintf(log_file, "page::%lu;"
-					" new style: calculated = %lu;"
-					" crc32 = %u; recorded = %lu\n",
+					" new style: calculated = " ULINTPF ";"
+					" crc32 = %u; recorded = " ULINTPF "\n",
 					page_no,
 					buf_calc_page_new_checksum(read_buf),
 					buf_calc_page_crc32(read_buf),
@@ -944,6 +982,24 @@ buf_page_is_corrupted(
 			return(FALSE);
 		}
 
+		/* We need to check whether the stored checksum matches legacy
+		big endian checksum or Innodb checksum. We optimize the order
+		based on earlier results. if earlier we have found pages
+		matching legacy big endian checksum, we try to match it first.
+		Otherwise we check innodb checksum first. */
+		if (legacy_big_endian_checksum) {
+			if (buf_page_is_checksum_valid_crc32(read_buf,
+				checksum_field1, checksum_field2,
+#ifdef UNIV_INNOCHECKSUM
+				page_no, is_log_enabled, log_file, curr_algo,
+#endif /* UNIV_INNOCHECKSUM */
+				true)) {
+
+				return(FALSE);
+			}
+			legacy_checksum_checked = true;
+		}
+
 		if (buf_page_is_checksum_valid_innodb(read_buf,
 			checksum_field1, checksum_field2
 #ifdef UNIV_INNOCHECKSUM
@@ -961,6 +1017,18 @@ buf_page_is_corrupted(
 			return(FALSE);
 		}
 
+		/* If legacy checksum is not checked, do it now. */
+		if (!legacy_checksum_checked && buf_page_is_checksum_valid_crc32(
+			read_buf, checksum_field1, checksum_field2,
+#ifdef UNIV_INNOCHECKSUM
+			page_no, is_log_enabled, log_file, curr_algo,
+#endif /* UNIV_INNOCHECKSUM */
+			true)) {
+
+				legacy_big_endian_checksum = true;
+				return(FALSE);
+		}
+
 #ifdef UNIV_INNOCHECKSUM
 		if (is_log_enabled) {
 			fprintf(log_file, "Fail; page %lu"
@@ -1016,12 +1084,19 @@ buf_page_is_corrupted(
 			return(FALSE);
 		}
 
-		if (buf_page_is_checksum_valid_crc32(read_buf,
-			checksum_field1, checksum_field2
 #ifdef UNIV_INNOCHECKSUM
-			, page_no, is_log_enabled, log_file, curr_algo)) {
+		if (buf_page_is_checksum_valid_crc32(read_buf,
+			checksum_field1, checksum_field2,
+			page_no, is_log_enabled, log_file, curr_algo, false)
+		    || buf_page_is_checksum_valid_crc32(read_buf,
+			checksum_field1, checksum_field2,
+			page_no, is_log_enabled, log_file, curr_algo, true)) {
 #else /* UNIV_INNOCHECKSUM */
-		)) {
+		if (buf_page_is_checksum_valid_crc32(read_buf,
+			checksum_field1, checksum_field2, false)
+		    || buf_page_is_checksum_valid_crc32(read_buf,
+			checksum_field1, checksum_field2, true)) {
+
 			if (curr_algo
 			    == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB) {
 				page_warn_strict_checksum(
@@ -1054,12 +1129,19 @@ buf_page_is_corrupted(
 			return(false);
 		}
 
-		if (buf_page_is_checksum_valid_crc32(read_buf,
-			checksum_field1, checksum_field2
 #ifdef UNIV_INNOCHECKSUM
-			, page_no, is_log_enabled, log_file, curr_algo)) {
+		if (buf_page_is_checksum_valid_crc32(read_buf,
+			checksum_field1, checksum_field2,
+			page_no, is_log_enabled, log_file, curr_algo, false)
+		    || buf_page_is_checksum_valid_crc32(read_buf,
+			checksum_field1, checksum_field2,
+			page_no, is_log_enabled, log_file, curr_algo, true)) {
 #else /* UNIV_INNOCHECKSUM */
-		)) {
+		if (buf_page_is_checksum_valid_crc32(read_buf,
+			checksum_field1, checksum_field2, false)
+		    || buf_page_is_checksum_valid_crc32(read_buf,
+			checksum_field1, checksum_field2, true)) {
+
 			page_warn_strict_checksum(
 				curr_algo,
 				SRV_CHECKSUM_ALGORITHM_CRC32,
@@ -1469,9 +1551,9 @@ buf_chunk_init(
 		return(NULL);
 	}
 
-#ifdef HAVE_LIBNUMA
+#if defined(HAVE_LIBNUMA) && defined(WITH_NUMA)
 	if (srv_numa_interleave) {
-		int	st = mbind(chunk->mem, mem_size,
+		int	st = mbind(chunk->mem, chunk->mem_size(),
 				   MPOL_INTERLEAVE,
 				   numa_all_nodes_ptr->maskp,
 				   numa_all_nodes_ptr->size,
@@ -1482,7 +1564,8 @@ buf_chunk_init(
 				" (error: " << strerror(errno) << ").";
 		}
 	}
-#endif // HAVE_LIBNUMA
+#endif /* HAVE_LIBNUMA && WITH_NUMA */
+
 
 	/* Allocate the block descriptors from
 	the start of the memory block. */
@@ -1891,7 +1974,6 @@ buf_pool_free_instance(
 	hash_table_free(buf_pool->page_hash);
 	hash_table_free(buf_pool->zip_hash);
 
-	buf_pool->allocator.~ut_allocator();
 	/* Free all used temporary slots */
 	if (buf_pool->tmp_arr) {
 		for(ulint i = 0; i < buf_pool->tmp_arr->n_slots; i++) {
@@ -1912,11 +1994,13 @@ buf_pool_free_instance(
 				slot->comp_buf_free = NULL;
 			}
 		}
+
+		ut_free(buf_pool->tmp_arr->slots);
+		ut_free(buf_pool->tmp_arr);
+		buf_pool->tmp_arr = NULL;
 	}
 
-	ut_free(buf_pool->tmp_arr->slots);
-	ut_free(buf_pool->tmp_arr);
-	buf_pool->tmp_arr = NULL;
+	buf_pool->allocator.~ut_allocator();
 }
 
 /********************************************************************//**
@@ -1935,33 +2019,17 @@ buf_pool_init(
 	ut_ad(n_instances <= MAX_BUFFER_POOLS);
 	ut_ad(n_instances == srv_buf_pool_instances);
 
+	NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE;
+
 	buf_pool_resizing = false;
 	buf_pool_withdrawing = false;
 	buf_withdraw_clock = 0;
 
-#ifdef HAVE_LIBNUMA
-	if (srv_numa_interleave) {
-		ib::info() << "Setting NUMA memory policy to MPOL_INTERLEAVE";
-		if (set_mempolicy(MPOL_INTERLEAVE,
-				  numa_all_nodes_ptr->maskp,
-				  numa_all_nodes_ptr->size) != 0) {
-			ib::warn() << "Failed to set NUMA memory policy to"
-				" MPOL_INTERLEAVE: " << strerror(errno);
-		}
-	}
-#endif // HAVE_LIBNUMA
-
 	buf_pool_ptr = (buf_pool_t*) ut_zalloc_nokey(
 		n_instances * sizeof *buf_pool_ptr);
 
 	buf_chunk_map_reg = UT_NEW_NOKEY(buf_pool_chunk_map_t());
 
-	ut_d(buf_chunk_map_latch = static_cast<rw_lock_t*>(
-			ut_zalloc_nokey(sizeof(*buf_chunk_map_latch))));
-
-	ut_d(rw_lock_create(
-		buf_chunk_map_latch_key, buf_chunk_map_latch, SYNC_ANY_LATCH));
-
 	for (i = 0; i < n_instances; i++) {
 		buf_pool_t*	ptr	= &buf_pool_ptr[i];
 
@@ -1981,18 +2049,6 @@ buf_pool_init(
 
 	btr_search_sys_create(buf_pool_get_curr_size() / sizeof(void*) / 64);
 
-#ifdef HAVE_LIBNUMA
-	if (srv_numa_interleave) {
-		ib::info() << "Setting NUMA memory policy to MPOL_DEFAULT";
-		if (set_mempolicy(MPOL_DEFAULT, NULL, 0) != 0) {
-			ib::warn() << "Failed to set NUMA memory policy to"
-				" MPOL_DEFAULT: " << strerror(errno);
-		}
-	}
-#endif // HAVE_LIBNUMA
-
-	buf_flush_event = os_event_create(0);
-
 	return(DB_SUCCESS);
 }
 
@@ -2008,10 +2064,6 @@ buf_pool_free(
 		buf_pool_free_instance(buf_pool_from_array(i));
 	}
 
-	ut_d(rw_lock_free(buf_chunk_map_latch));
-	ut_d(ut_free(buf_chunk_map_latch));
-	ut_d(buf_chunk_map_latch = NULL);
-
 	UT_DELETE(buf_chunk_map_reg);
 	buf_chunk_map_reg = buf_chunk_map_ref = NULL;
 
@@ -2561,6 +2613,8 @@ buf_pool_resize()
 	ulint		new_instance_size;
 	bool		warning = false;
 
+	NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE;
+
 	ut_ad(!buf_pool_resizing);
 	ut_ad(!buf_pool_withdrawing);
 	ut_ad(srv_buf_pool_chunk_unit > 0);
@@ -2958,9 +3012,7 @@ buf_pool_resize()
 		}
 	}
 
-	ut_d(rw_lock_x_lock(buf_chunk_map_latch));
 	UT_DELETE(chunk_map_old);
-	ut_d(rw_lock_x_unlock(buf_chunk_map_latch));
 
 	buf_pool_resizing = false;
 
@@ -3028,14 +3080,12 @@ when waked up either performs a resizing and sleeps again.
 extern "C"
 os_thread_ret_t
 DECLARE_THREAD(buf_resize_thread)(
-	void*	arg __attribute__((unused)))
+	void*	arg MY_ATTRIBUTE((unused)))
 {
 	my_thread_init();
 
 	srv_buf_resize_thread_active = true;
 
-	buf_resize_status("not started");
-
 	while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
 		os_event_wait(srv_buf_resize_event);
 		os_event_reset(srv_buf_resize_event);
@@ -3063,7 +3113,7 @@ DECLARE_THREAD(buf_resize_thread)(
 	srv_buf_resize_thread_active = false;
 
 	my_thread_end();
-	os_thread_exit(NULL);
+	os_thread_exit();
 
 	OS_THREAD_DUMMY_RETURN;
 }
@@ -3666,6 +3716,7 @@ buf_page_get_zip(
 	ibool		discard_attempted = FALSE;
 	ibool		must_read;
 	buf_pool_t*	buf_pool = buf_pool_get(page_id);
+	buf_page_t*	rpage = NULL;
 
 	buf_pool->stat.n_page_gets++;
 
@@ -3684,7 +3735,7 @@ buf_page_get_zip(
 		/* Page not in buf_pool: needs to be read from file */
 
 		ut_ad(!hash_lock);
-		buf_read_page(page_id, page_size, NULL);
+		buf_read_page(page_id, page_size, &rpage);
 
 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
 		ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -3873,150 +3924,44 @@ buf_zip_decompress(
 }
 
 #ifndef UNIV_HOTBACKUP
-/*******************************************************************//**
-Gets the block to whose frame the pointer is pointing to.
+/** Get a buffer block from an adaptive hash index pointer.
+This function does not return if the block is not identified.
+ at param[in]	ptr	pointer to within a page frame
 @return pointer to block, never NULL */
 buf_block_t*
-buf_block_align(
-/*============*/
-	const byte*	ptr)	/*!< in: pointer to a frame */
+buf_block_from_ahi(const byte* ptr)
 {
 	buf_pool_chunk_map_t::iterator it;
 
-	ut_ad(srv_buf_pool_chunk_unit > 0);
-
-	/* TODO: This might be still optimistic treatment.
-	buf_pool_resize() needs all buf_pool_mutex and all
-	buf_pool->page_hash x-latched until actual modification.
-	It should block the other user threads and should take while
-	which is enough to done the buf_pool_chunk_map access. */
-	while (buf_pool_resizing) {
-		/* buf_pool_chunk_map is being modified */
-		os_thread_sleep(100000); /* 0.1 sec */
-	}
-
-	ulint	counter = 0;
-retry:
-#ifdef UNIV_DEBUG
-	bool resize_disabled = (buf_disable_resize_buffer_pool_debug != FALSE);
-	if (!resize_disabled) {
-		rw_lock_s_lock(buf_chunk_map_latch);
-	}
-#endif /* UNIV_DEBUG */
 	buf_pool_chunk_map_t*	chunk_map = buf_chunk_map_ref;
+	ut_ad(buf_chunk_map_ref == buf_chunk_map_reg);
+	ut_ad(!buf_pool_resizing);
 
-	if (ptr < reinterpret_cast<byte*>(srv_buf_pool_chunk_unit)) {
-		it = chunk_map->upper_bound(0);
-	} else {
-		it = chunk_map->upper_bound(
-			ptr - srv_buf_pool_chunk_unit);
-	}
+	const byte* bound = reinterpret_cast<uintptr_t>(ptr)
+			    > srv_buf_pool_chunk_unit
+			    ? ptr - srv_buf_pool_chunk_unit : 0;
+	it = chunk_map->upper_bound(bound);
 
-	if (it == chunk_map->end()) {
-#ifdef UNIV_DEBUG
-		if (!resize_disabled) {
-			rw_lock_s_unlock(buf_chunk_map_latch);
-		}
-#endif /* UNIV_DEBUG */
-		/* The block should always be found. */
-		++counter;
-		ut_a(counter < 10);
-		os_thread_sleep(100000); /* 0.1 sec */
-		goto retry;
-	}
+	ut_a(it != chunk_map->end());
 
 	buf_chunk_t*	chunk = it->second;
-#ifdef UNIV_DEBUG
-	if (!resize_disabled) {
-		rw_lock_s_unlock(buf_chunk_map_latch);
-	}
-#endif /* UNIV_DEBUG */
-
 	ulint		offs = ptr - chunk->blocks->frame;
 
 	offs >>= UNIV_PAGE_SIZE_SHIFT;
 
-	if (offs < chunk->size) {
-		buf_block_t*	block = &chunk->blocks[offs];
+	ut_a(offs < chunk->size);
 
-		/* The function buf_chunk_init() invokes
-		buf_block_init() so that block[n].frame ==
-		block->frame + n * UNIV_PAGE_SIZE.  Check it. */
-		ut_ad(block->frame == page_align(ptr));
-#ifdef UNIV_DEBUG
-		/* A thread that updates these fields must
-		hold buf_pool->mutex and block->mutex.  Acquire
-		only the latter. */
-		buf_page_mutex_enter(block);
+	buf_block_t*	block = &chunk->blocks[offs];
 
-		switch (buf_block_get_state(block)) {
-		case BUF_BLOCK_POOL_WATCH:
-		case BUF_BLOCK_ZIP_PAGE:
-		case BUF_BLOCK_ZIP_DIRTY:
-			/* These types should only be used in
-			the compressed buffer pool, whose
-			memory is allocated from
-			buf_pool->chunks, in UNIV_PAGE_SIZE
-			blocks flagged as BUF_BLOCK_MEMORY. */
-			ut_error;
-			break;
-		case BUF_BLOCK_NOT_USED:
-		case BUF_BLOCK_READY_FOR_USE:
-		case BUF_BLOCK_MEMORY:
-			/* Some data structures contain
-			"guess" pointers to file pages.  The
-			file pages may have been freed and
-			reused.  Do not complain. */
-			break;
-		case BUF_BLOCK_REMOVE_HASH:
-			/* buf_LRU_block_remove_hashed_page()
-			will overwrite the FIL_PAGE_OFFSET and
-			FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID with
-			0xff and set the state to
-			BUF_BLOCK_REMOVE_HASH. */
-# ifndef UNIV_DEBUG_VALGRIND
-			/* In buf_LRU_block_remove_hashed() we
-			explicitly set those values to 0xff and
-			declare them uninitialized with
-			UNIV_MEM_INVALID() after that. */
-			ut_ad(page_get_space_id(page_align(ptr))
-			      == 0xffffffff);
-			ut_ad(page_get_page_no(page_align(ptr))
-			      == 0xffffffff);
-# endif /* UNIV_DEBUG_VALGRIND */
-			break;
-			case BUF_BLOCK_FILE_PAGE:
-			const ulint	space_id1 = block->page.id.space();
-			const ulint	page_no1 = block->page.id.page_no();
-			const ulint	space_id2 = page_get_space_id(
-							page_align(ptr));
-			const ulint	page_no2= page_get_page_no(
-							page_align(ptr));
-
-			if (space_id1 != space_id2 || page_no1 != page_no2) {
-
-				ib::error() << "Found a mismatch page,"
-					<< " expect page "
-					<< page_id_t(space_id1, page_no1)
-					<< " but found "
-					<< page_id_t(space_id2, page_no2);
-
-				ut_ad(0);
-			}
-			break;
-		}
-
-		buf_page_mutex_exit(block);
-#endif /* UNIV_DEBUG */
-
-		return(block);
-	}
-
-	/* The block should always be found. */
-	++counter;
-	ut_a(counter < 10);
-	os_thread_sleep(100000); /* 0.1 sec */
-	goto retry;
+	/* The function buf_chunk_init() invokes buf_block_init() so that
+	block[n].frame == block->frame + n * UNIV_PAGE_SIZE.  Check it. */
+	ut_ad(block->frame == page_align(ptr));
+	/* Read the state of the block without holding a mutex.
+	A state transition from BUF_BLOCK_FILE_PAGE to
+	BUF_BLOCK_REMOVE_HASH is possible during this execution. */
+	ut_d(const buf_page_state state = buf_block_get_state(block));
+	ut_ad(state == BUF_BLOCK_FILE_PAGE || state == BUF_BLOCK_REMOVE_HASH);
+	return(block);
 }
 
 /********************************************************************//**
@@ -5657,6 +5602,7 @@ buf_page_create(
 	/* These 8 bytes are also repurposed for PageIO compression and must
 	be reset when the frame is assigned to a new page id. See fil0fil.h.
 
+
 	FIL_PAGE_FILE_FLUSH_LSN is used on the following pages:
 	(1) The first page of the InnoDB system tablespace (page 0:0)
 	(2) FIL_RTREE_SPLIT_SEQ_NUM on R-tree pages .
@@ -5948,7 +5894,7 @@ buf_page_io_complete(
 		ulint	read_page_no;
 		ulint	read_space_id;
 		byte*	frame;
-		bool	compressed_page;
+		bool	compressed_page=false;
 
 		ut_ad(bpage->zip.data != NULL || ((buf_block_t*)bpage)->frame != NULL);
 
@@ -6009,6 +5955,7 @@ buf_page_io_complete(
 				<< ", should be " << bpage->id;
 		}
 
+#ifdef MYSQL_COMPRESSION
 		compressed_page = Compression::is_compressed_page(frame);
 
 		/* If the decompress failed then the most likely case is
@@ -6026,6 +5973,7 @@ buf_page_io_complete(
 				<< Compression::to_string(meta) << " "
 				<< "that is not supported by this instance";
 		}
+#endif /* MYSQL_COMPRESSION */
 
 		/* From version 3.23.38 up we store the page checksum
 		to the 4 first bytes of the page end lsn field */
@@ -6064,7 +6012,7 @@ buf_page_io_complete(
 
 				ib::info()
 					<< "It is also possible that your"
-				        " operating system has corrupted"
+					" operating system has corrupted"
 					" its own file cache and rebooting"
 					" your computer removes the error."
 					" If the corrupt page is an index page."
@@ -6125,7 +6073,9 @@ buf_page_io_complete(
 		/* If space is being truncated then avoid ibuf operation.
 		During re-init we have already freed ibuf entries. */
 		if (uncompressed
+#ifdef MYSQL_COMPRESSION
 		    && !Compression::is_compressed_page(frame)
+#endif /* MYSQL_COMPRESSION */
 		    && !recv_no_ibuf_operations
 		    && !Tablespace::is_undo_tablespace(bpage->id.space())
 		    && bpage->id.space() != srv_tmp_space.space_id()
@@ -7143,8 +7093,9 @@ buf_print_io_instance(
 	/* Print some values to help us with visualizing what is
 	happening with LRU eviction. */
 	fprintf(file,
-		"LRU len: %lu, unzip_LRU len: %lu\n"
-		"I/O sum[%lu]:cur[%lu], unzip sum[%lu]:cur[%lu]\n",
+		"LRU len: " ULINTPF ", unzip_LRU len: " ULINTPF "\n"
+		"I/O sum[" ULINTPF "]:cur[" ULINTPF "], "
+		"unzip sum[" ULINTPF "]:cur[" ULINTPF "]\n",
 		pool_info->lru_len, pool_info->unzip_lru_len,
 		pool_info->io_sum, pool_info->io_cur,
 		pool_info->unzip_sum, pool_info->unzip_cur);
@@ -7205,7 +7156,7 @@ buf_print_io(
 		"----------------------\n", file);
 
 		for (i = 0; i < srv_buf_pool_instances; i++) {
-			fprintf(file, "---BUFFER POOL %lu\n", i);
+			fprintf(file, "---BUFFER POOL " ULINTPF "\n", i);
 			buf_print_io_instance(&pool_info[i], file);
 		}
 	}
@@ -7683,3 +7634,4 @@ buf_page_decrypt_after_read(
 	return (success);
 }
 #endif /* !UNIV_INNOCHECKSUM */
+
diff --git a/storage/innobase/buf/buf0checksum.cc b/storage/innobase/buf/buf0checksum.cc
index 935c8a7..94eafec 100644
--- a/storage/innobase/buf/buf0checksum.cc
+++ b/storage/innobase/buf/buf0checksum.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, 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
@@ -30,9 +30,9 @@ Created Aug 11, 2011 Vasil Dimov
 #include "buf0checksum.h"
 
 #ifndef UNIV_INNOCHECKSUM
-
 #include "srv0srv.h"
 #endif /* !UNIV_INNOCHECKSUM */
+
 #include "buf0types.h"
 
 /** the macro MYSQL_SYSVAR_ENUM() requires "long unsigned int" and if we
@@ -41,6 +41,8 @@ ha_innodb.cc:12251: error: cannot convert 'srv_checksum_algorithm_t*' to
   'long unsigned int*' in initialization */
 ulong	srv_checksum_algorithm = SRV_CHECKSUM_ALGORITHM_INNODB;
 
+/** set if we have found pages matching legacy big endian checksum */
+bool	legacy_big_endian_checksum = false;
 /** Calculates the CRC32 checksum of a page. The value is stored to the page
 when it is written to a file and also checked for a match when reading from
 the file. When reading we allow both normal CRC32 and CRC-legacy-big-endian
diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc
index 64ecb54..ff1d205 100644
--- a/storage/innobase/buf/buf0dblwr.cc
+++ b/storage/innobase/buf/buf0dblwr.cc
@@ -173,7 +173,7 @@ buf_dblwr_init(
 Creates the doublewrite buffer to a new InnoDB installation. The header of the
 doublewrite buffer is placed on the trx system header page.
 @return true if successful, false if not. */
-__attribute__((warn_unused_result))
+MY_ATTRIBUTE((warn_unused_result))
 bool
 buf_dblwr_create(void)
 /*==================*/
@@ -576,7 +576,7 @@ buf_dblwr_process(void)
 			MLOG_TRUNCATE record in redo. */
 			bool	skip_warning =
 				srv_is_tablespace_truncated(space_id)
-				|| srv_was_tablespace_truncated(space_id);
+				|| srv_was_tablespace_truncated(space);
 
 			if (!skip_warning) {
 				ib::warn() << "Page " << page_no_dblwr
@@ -602,6 +602,14 @@ buf_dblwr_process(void)
 				page_id, page_size,
 				0, page_size.physical(), read_buf, NULL, NULL);
 
+			if (err != DB_SUCCESS) {
+
+				ib::warn()
+					<< "Double write buffer recovery: "
+					<< page_id << " read failed with "
+					<< "error: " << ut_strerr(err);
+			}
+
 			/* Is page compressed ? */
 			is_compressed = fil_page_is_compressed_encrypted(read_buf) |
 				fil_page_is_compressed(read_buf);
@@ -1187,6 +1195,7 @@ buf_dblwr_add_to_batch(
 	} else {
 		ut_a(buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE);
 
+
 		UNIV_MEM_ASSERT_RW(frame,
 				   bpage->size.logical());
 
diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc
index 831dd13..ede7b02 100644
--- a/storage/innobase/buf/buf0dump.cc
+++ b/storage/innobase/buf/buf0dump.cc
@@ -184,6 +184,25 @@ buf_load_status(
 	va_end(ap);
 }
 
+/** Returns the directory path where the buffer pool dump file will be created.
+ at return directory path */
+static
+const char*
+get_buf_dump_dir()
+{
+	const char*	dump_dir;
+
+	/* The dump file should be created in the default data directory if
+	innodb_data_home_dir is set as an empty string. */
+	if (strcmp(srv_data_home, "") == 0) {
+		dump_dir = fil_path_to_mysql_datadir;
+	} else {
+		dump_dir = srv_data_home;
+	}
+
+	return(dump_dir);
+}
+
 /** Generate the path to the buffer pool dump/load file.
 @param[out]	path		generated path
 @param[in]	path_size	size of 'path', used as in snprintf(3). */
@@ -195,7 +214,7 @@ buf_dump_generate_path(
 {
 	char	buf[FN_REFLEN];
 
-	ut_snprintf(buf, sizeof(buf), "%s%c%s", srv_data_home,
+	ut_snprintf(buf, sizeof(buf), "%s%c%s", get_buf_dump_dir(),
 		    OS_PATH_SEPARATOR, srv_buf_dump_filename);
 
 	os_file_type_t	type;
@@ -217,7 +236,7 @@ buf_dump_generate_path(
 		and append srv_buf_dump_filename to it. */
 		char	srv_data_home_full[FN_REFLEN];
 
-		my_realpath(srv_data_home_full, srv_data_home, 0);
+		my_realpath(srv_data_home_full, get_buf_dump_dir(), 0);
 
 		if (srv_data_home_full[strlen(srv_data_home_full) - 1]
 		    == OS_PATH_SEPARATOR) {
@@ -549,13 +568,22 @@ buf_load()
 		dump_n = total_buffer_pools_pages;
 	}
 
-	dump = static_cast<buf_dump_t*>(ut_malloc_nokey(dump_n
-							* sizeof(*dump)));
+	if(dump_n != 0) {
+		dump = static_cast<buf_dump_t*>(ut_malloc_nokey(
+				dump_n * sizeof(*dump)));
+	} else {
+		fclose(f);
+		ut_sprintf_timestamp(now);
+		buf_load_status(STATUS_INFO,
+				"Buffer pool(s) load completed at %s"
+				" (%s was empty)", now, full_filename);
+		return;
+	}
 
 	if (dump == NULL) {
 		fclose(f);
 		buf_load_status(STATUS_ERR,
-				"Cannot allocate " ULINTPF " bytes: %s",
+				"Cannot allocate %lu bytes: %s",
 				(ulint) (dump_n * sizeof(*dump)),
 				strerror(errno));
 		return;
@@ -767,8 +795,8 @@ DECLARE_THREAD(buf_dump_thread)(
 
 	srv_buf_dump_thread_active = TRUE;
 
-	buf_dump_status(STATUS_VERBOSE, "not started");
-	buf_load_status(STATUS_VERBOSE, "not started");
+	buf_dump_status(STATUS_VERBOSE, "Dumping of buffer pool not started");
+	buf_load_status(STATUS_VERBOSE, "Loading of buffer pool not started");
 
 	if (srv_buffer_pool_load_at_startup) {
 		buf_load();
@@ -800,7 +828,7 @@ DECLARE_THREAD(buf_dump_thread)(
 
 	/* We count the number of threads in os_thread_exit(). A created
 	thread should always use that to exit and not use return() to exit. */
-	os_thread_exit(NULL);
+	os_thread_exit();
 
 	OS_THREAD_DUMMY_RETURN;
 }
diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc
index 227c71c..8c7c9f6 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2016, Oracle and/or its affiliates
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
 Copyright (c) 2013, 2016, MariaDB Corporation
 Copyright (c) 2013, 2014, Fusion-io
 
@@ -27,6 +27,7 @@ Created 11/11/1995 Heikki Tuuri
 
 #include "ha_prototypes.h"
 #include <mysql/service_thd_wait.h>
+#include <my_dbug.h>
 
 #include "buf0flu.h"
 
@@ -86,6 +87,7 @@ static lsn_t lsn_avg_rate = 0;
 
 /** Target oldest LSN for the requested flush_sync */
 static lsn_t buf_flush_sync_lsn = 0;
+
 #ifdef UNIV_PFS_THREAD
 mysql_pfs_key_t page_cleaner_thread_key;
 #endif /* UNIV_PFS_THREAD */
@@ -180,10 +182,20 @@ struct page_cleaner_t {
 	page_cleaner_slot_t*	slots;		/*!< pointer to the slots */
 	bool			is_running;	/*!< false if attempt
 						to shutdown */
+
+#ifdef UNIV_DEBUG
+	ulint			n_disabled_debug;
+						/*<! how many of pc threads
+						have been disabled */
+#endif /* UNIV_DEBUG */
 };
 
 static page_cleaner_t*	page_cleaner = NULL;
 
+#ifdef UNIV_DEBUG
+my_bool innodb_page_cleaner_disabled_debug;
+#endif /* UNIV_DEBUG */
+
 /** If LRU list of a buf_pool is less than this size then LRU eviction
 should not happen. This is because when we do LRU flushing we also put
 the blocks on free list. If LRU list is very small then we can end up
@@ -998,7 +1010,7 @@ buf_flush_write_block_low(
 	bool		sync)		/*!< in: true if sync IO request */
 {
 	page_t*	frame = NULL;
-	ulint space_id          = bpage->id.space();
+	ulint space_id = bpage->id.space();
 	atomic_writes_t awrites = fil_space_get_atomic_writes(space_id);
 
 #ifdef UNIV_DEBUG
@@ -1603,7 +1615,7 @@ The calling thread is not allowed to own any latches on pages!
 It attempts to make 'max' blocks available in the free list. Note that
 it is a best effort attempt and it is not guaranteed that after a call
 to this function there will be 'max' blocks in the free list.*/
-__attribute__((nonnull))
+
 void
 buf_flush_LRU_list_batch(
 /*=====================*/
@@ -1624,9 +1636,7 @@ buf_flush_LRU_list_batch(
 	n->flushed = 0;
 	n->evicted = 0;
 	n->unzip_LRU_evicted = 0;
-
 	ut_ad(buf_pool_mutex_own(buf_pool));
-
 	if (buf_pool->curr_size < buf_pool->old_size
 	    && buf_pool->withdraw_target > 0) {
 		withdraw_depth = buf_pool->withdraw_target
@@ -1704,7 +1714,7 @@ buf_flush_LRU_list_batch(
 /*******************************************************************//**
 Flush and move pages from LRU or unzip_LRU list to the free list.
 Whether LRU or unzip_LRU is used depends on the state of the system.*/
-__attribute__((nonnull))
+
 static
 void
 buf_do_LRU_batch(
@@ -1830,7 +1840,7 @@ BUF_FLUSH_LIST, then the caller must not own any latches on pages
 not guaranteed that the actual number is that big, though)
 @param[in]	lsn_limit	in the case of BUF_FLUSH_LIST all blocks whose
 oldest_modification is smaller than this should be flushed (if their number
-does not exceed min_n), otherwise ignored*/
+does not exceed min_n), otherwise ignored */
 void
 buf_flush_batch(
 	buf_pool_t*		buf_pool,
@@ -2003,6 +2013,7 @@ buf_flush_wait_batch_end(
 }
 
 /** Do flushing batch of a given type.
+NOTE: The calling thread is not allowed to own any latches on pages!
 @param[in,out]	buf_pool	buffer pool instance
 @param[in]	type		flush type
 @param[in]	min_n		wished minimum mumber of blocks flushed
@@ -2010,7 +2021,7 @@ buf_flush_wait_batch_end(
 @param[in]	lsn_limit	in the case BUF_FLUSH_LIST all blocks whose
 oldest_modification is smaller than this should be flushed (if their number
 does not exceed min_n), otherwise ignored
- at param[out]	n		the number of pages which were processed is
+ at param[out]	n_processed	the number of pages which were processed is
 passed back to caller. Ignored if NULL
 @retval true	if a batch was queued successfully.
 @retval false	if another batch of same type was already running. */
@@ -2038,7 +2049,6 @@ buf_flush_do_batch(
 
 	return(true);
 }
-
 /**
 Waits until a flush batch of the given lsn ends
 @param[in]	new_oldest	target oldest_modified_lsn to wait for */
@@ -2136,6 +2146,7 @@ buf_flush_lists(
 		buf_pool_t*		buf_pool;
 		flush_counters_t	n;
 
+		memset(&n, 0, sizeof(flush_counters_t));
 		buf_pool = buf_pool_from_array(i);
 
 		if (!buf_flush_do_batch(buf_pool,
@@ -2237,10 +2248,8 @@ buf_flush_single_page_from_LRU(
 		} else {
 			mutex_exit(block_mutex);
 		}
-
 		ut_ad(!mutex_own(block_mutex));
 	}
-
 	if (!freed) {
 		/* Can't find a single flushable page. */
 		ut_ad(!bpage);
@@ -2255,6 +2264,8 @@ buf_flush_single_page_from_LRU(
 			scanned);
 	}
 
+
+
 	ut_ad(!buf_pool_mutex_own(buf_pool));
 	return(freed);
 }
@@ -2283,12 +2294,10 @@ buf_flush_LRU_list(
 	}
 
 	ut_ad(buf_pool);
-
 	/* srv_LRU_scan_depth can be arbitrarily large value.
 	We cap it with current LRU size. */
 	buf_pool_mutex_enter(buf_pool);
 	scan_depth = UT_LIST_GET_LEN(buf_pool->LRU);
-
 	if (buf_pool->curr_size < buf_pool->old_size
 	    && buf_pool->withdraw_target > 0) {
 		withdraw_depth = buf_pool->withdraw_target
@@ -2296,16 +2305,13 @@ buf_flush_LRU_list(
 	} else {
 		withdraw_depth = 0;
 	}
-
 	buf_pool_mutex_exit(buf_pool);
-
 	if (withdraw_depth > srv_LRU_scan_depth) {
 		scan_depth = ut_min(withdraw_depth, scan_depth);
 	} else {
 		scan_depth = ut_min(static_cast<ulint>(srv_LRU_scan_depth),
 				    scan_depth);
 	}
-
 	/* Currently one of page_cleaners is the only thread
 	that can trigger an LRU flush at the same time.
 	So, it is not possible that a batch triggered during
@@ -2328,6 +2334,7 @@ buf_flush_LRU_lists(void)
 {
 	ulint	n_flushed = 0;
 	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
+
 		n_flushed += buf_flush_LRU_list(buf_pool_from_array(i));
 	}
 
@@ -2718,8 +2725,6 @@ pc_sleep_if_needed(
 	return(OS_SYNC_TIME_EXCEEDED);
 }
 
-
-
 /******************************************************************//**
 Initialize page_cleaner. */
 void
@@ -2742,6 +2747,8 @@ buf_flush_page_cleaner_init(void)
 		ut_zalloc_nokey(page_cleaner->n_slots
 				* sizeof(*page_cleaner->slots)));
 
+	ut_d(page_cleaner->n_disabled_debug = 0);
+
 	page_cleaner->is_running = true;
 }
 
@@ -2997,6 +3004,122 @@ buf_flush_page_cleaner_set_priority(
 }
 #endif /* UNIV_LINUX */
 
+#ifdef UNIV_DEBUG
+/** Loop used to disable page cleaner threads. */
+static
+void
+buf_flush_page_cleaner_disabled_loop(void)
+{
+	ut_ad(page_cleaner != NULL);
+
+	if (!innodb_page_cleaner_disabled_debug) {
+		/* We return to avoid entering and exiting mutex. */
+		return;
+	}
+
+	mutex_enter(&page_cleaner->mutex);
+	page_cleaner->n_disabled_debug++;
+	mutex_exit(&page_cleaner->mutex);
+
+	while (innodb_page_cleaner_disabled_debug
+	       && srv_shutdown_state == SRV_SHUTDOWN_NONE
+	       && page_cleaner->is_running) {
+
+		os_thread_sleep(100000); /* [A] */
+	}
+
+	/* We need to wait for threads exiting here, otherwise we would
+	encounter problem when we quickly perform following steps:
+		1) SET GLOBAL innodb_page_cleaner_disabled_debug = 1;
+		2) SET GLOBAL innodb_page_cleaner_disabled_debug = 0;
+		3) SET GLOBAL innodb_page_cleaner_disabled_debug = 1;
+	That's because after step 1 this thread could still be sleeping
+	inside the loop above at [A] and steps 2, 3 could happen before
+	this thread wakes up from [A]. In such case this thread would
+	not re-increment n_disabled_debug and we would be waiting for
+	him forever in buf_flush_page_cleaner_disabled_debug_update(...).
+
+	Therefore we are waiting in step 2 for this thread exiting here. */
+
+	mutex_enter(&page_cleaner->mutex);
+	page_cleaner->n_disabled_debug--;
+	mutex_exit(&page_cleaner->mutex);
+}
+
+/** Disables page cleaner threads (coordinator and workers).
+It's used by: SET GLOBAL innodb_page_cleaner_disabled_debug = 1 (0).
+ at param[in]	thd		thread handle
+ at param[in]	var		pointer to system variable
+ at param[out]	var_ptr		where the formal string goes
+ at param[in]	save		immediate result from check function */
+void
+buf_flush_page_cleaner_disabled_debug_update(
+	THD*				thd,
+	struct st_mysql_sys_var*	var,
+	void*				var_ptr,
+	const void*			save)
+{
+	if (page_cleaner == NULL) {
+		return;
+	}
+
+	if (!*static_cast<const my_bool*>(save)) {
+		if (!innodb_page_cleaner_disabled_debug) {
+			return;
+		}
+
+		innodb_page_cleaner_disabled_debug = false;
+
+		/* Enable page cleaner threads. */
+		while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
+			mutex_enter(&page_cleaner->mutex);
+			const ulint n = page_cleaner->n_disabled_debug;
+			mutex_exit(&page_cleaner->mutex);
+			/* Check if all threads have been enabled, to avoid
+			problem when we decide to re-disable them soon. */
+			if (n == 0) {
+				break;
+			}
+		}
+		return;
+	}
+
+	if (innodb_page_cleaner_disabled_debug) {
+		return;
+	}
+
+	innodb_page_cleaner_disabled_debug = true;
+
+	while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
+		/* Workers are possibly sleeping on is_requested.
+
+		We have to wake them, otherwise they could possibly
+		have never noticed, that they should be disabled,
+		and we would wait for them here forever.
+
+		That's why we have sleep-loop instead of simply
+		waiting on some disabled_debug_event. */
+		os_event_set(page_cleaner->is_requested);
+
+		mutex_enter(&page_cleaner->mutex);
+
+		ut_ad(page_cleaner->n_disabled_debug
+		      <= srv_n_page_cleaners);
+
+		if (page_cleaner->n_disabled_debug
+		    == srv_n_page_cleaners) {
+
+			mutex_exit(&page_cleaner->mutex);
+			break;
+		}
+
+		mutex_exit(&page_cleaner->mutex);
+
+		os_thread_sleep(100000);
+	}
+}
+#endif /* UNIV_DEBUG */
+
 /******************************************************************//**
 page_cleaner thread tasked with flushing dirty pages from the buffer
 pools. As of now we'll have only one coordinator.
@@ -3014,6 +3137,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(
 	ulint	last_activity = srv_get_activity_count();
 	ulint	last_pages = 0;
 
+	my_thread_init();
 #ifdef UNIV_PFS_THREAD
 	/* JAN: TODO: MySQL 5.7 PSI
 	pfs_register_thread(page_cleaner_thread_key);
@@ -3132,6 +3256,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(
 					} else {
 						warn_interval *= 2;
 					}
+
 					warn_count = warn_interval;
 				} else {
 					--warn_count;
@@ -3268,6 +3393,8 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(
 			/* no activity, but woken up by event */
 			n_flushed = 0;
 		}
+
+		ut_d(buf_flush_page_cleaner_disabled_loop());
 	}
 
 	ut_ad(srv_shutdown_state > 0);
@@ -3367,7 +3494,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(
 
 	/* We count the number of threads in os_thread_exit(). A created
 	thread should always use that to exit and not use return() to exit. */
-	os_thread_exit(NULL);
+	os_thread_exit();
 
 	OS_THREAD_DUMMY_RETURN;
 }
@@ -3379,10 +3506,12 @@ extern "C"
 os_thread_ret_t
 DECLARE_THREAD(buf_flush_page_cleaner_worker)(
 /*==========================================*/
-	void*	arg __attribute__((unused)))
+	void*	arg MY_ATTRIBUTE((unused)))
 			/*!< in: a dummy parameter required by
 			os_thread_create */
 {
+	my_thread_init();
+
 	mutex_enter(&page_cleaner->mutex);
 	page_cleaner->n_workers++;
 	mutex_exit(&page_cleaner->mutex);
@@ -3401,6 +3530,8 @@ DECLARE_THREAD(buf_flush_page_cleaner_worker)(
 	while (true) {
 		os_event_wait(page_cleaner->is_requested);
 
+		ut_d(buf_flush_page_cleaner_disabled_loop());
+
 		if (!page_cleaner->is_running) {
 			break;
 		}
@@ -3412,7 +3543,9 @@ DECLARE_THREAD(buf_flush_page_cleaner_worker)(
 	page_cleaner->n_workers--;
 	mutex_exit(&page_cleaner->mutex);
 
-	os_thread_exit(NULL);
+	my_thread_end();
+
+	os_thread_exit();
 
 	OS_THREAD_DUMMY_RETURN;
 }
@@ -3549,7 +3682,6 @@ buf_flush_validate(
 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
 #endif /* !UNIV_HOTBACKUP */
 
-
 /******************************************************************//**
 Check if there are any dirty pages that belong to a space id in the flush
 list in a particular buffer pool.
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc
index 1cb46ae..5d20777 100644
--- a/storage/innobase/buf/buf0lru.cc
+++ b/storage/innobase/buf/buf0lru.cc
@@ -145,7 +145,7 @@ If a compressed page is freed other compressed pages may be relocated.
 caller needs to free the page to the free list
 @retval false if BUF_BLOCK_ZIP_PAGE was removed from page_hash. In
 this case the block is already returned to the buddy allocator. */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
 bool
 buf_LRU_block_remove_hashed(
 /*========================*/
@@ -376,7 +376,7 @@ want to hog the CPU and resources. Release the buffer pool and block
 mutex and try to force a context switch. Then reacquire the same mutexes.
 The current page is "fixed" before the release of the mutexes and then
 "unfixed" again once we have reacquired the mutexes. */
-static	MY_ATTRIBUTE((nonnull))
+static
 void
 buf_flush_yield(
 /*============*/
@@ -419,7 +419,7 @@ If we have hogged the resources for too long then release the buffer
 pool and flush list mutex and do a thread yield. Set the current page
 to "sticky" so that it is not relocated during the yield.
 @return true if yielded */
-static	MY_ATTRIBUTE((nonnull(1), warn_unused_result))
+static	MY_ATTRIBUTE((warn_unused_result))
 bool
 buf_flush_try_yield(
 /*================*/
@@ -462,7 +462,7 @@ buf_flush_try_yield(
 Removes a single page from a given tablespace inside a specific
 buffer pool instance.
 @return true if page was removed. */
-static	MY_ATTRIBUTE((nonnull, warn_unused_result))
+static	MY_ATTRIBUTE((warn_unused_result))
 bool
 buf_flush_or_remove_page(
 /*=====================*/
@@ -548,7 +548,7 @@ the list as they age towards the tail of the LRU.
 @retval DB_SUCCESS if all freed
 @retval DB_FAIL if not all freed
 @retval DB_INTERRUPTED if the transaction was interrupted */
-static	MY_ATTRIBUTE((nonnull(1), warn_unused_result))
+static	MY_ATTRIBUTE((warn_unused_result))
 dberr_t
 buf_flush_or_remove_pages(
 /*======================*/
@@ -668,7 +668,7 @@ Remove or flush all the dirty pages that belong to a given tablespace
 inside a specific buffer pool instance. The pages will remain in the LRU
 list and will be evicted from the LRU list as they age and move towards
 the tail of the LRU list. */
-static MY_ATTRIBUTE((nonnull(1)))
+static
 void
 buf_flush_dirty_pages(
 /*==================*/
@@ -717,7 +717,7 @@ buf_flush_dirty_pages(
 /******************************************************************//**
 Remove all pages that belong to a given tablespace inside a specific
 buffer pool instance when we are DISCARDing the tablespace. */
-static MY_ATTRIBUTE((nonnull))
+static
 void
 buf_LRU_remove_all_pages(
 /*=====================*/
@@ -856,7 +856,7 @@ buffer pool instance when we are deleting the data file(s) of that
 tablespace. The pages still remain a part of LRU and are evicted from
 the list as they age towards the tail of the LRU only if buf_remove
 is BUF_REMOVE_FLUSH_NO_WRITE. */
-static	MY_ATTRIBUTE((nonnull(1)))
+static
 void
 buf_LRU_remove_pages(
 /*=================*/
@@ -1902,7 +1902,7 @@ buf_LRU_free_page(
 	DBUG_PRINT("ib_buf", ("free page %u:%u",
 			      bpage->id.space(), bpage->id.page_no()));
 
-        ut_ad(rw_lock_own(hash_lock, RW_LOCK_X));
+	ut_ad(rw_lock_own(hash_lock, RW_LOCK_X));
 	ut_ad(buf_page_can_relocate(bpage));
 
 	if (!buf_LRU_block_remove_hashed(bpage, zip)) {
@@ -2102,8 +2102,9 @@ buf_LRU_block_free_non_file_page(
 	case BUF_BLOCK_READY_FOR_USE:
 		break;
 	default:
-		fprintf(stderr, "InnoDB: Error: Block %p incorrect state %s in buf_LRU_block_free_non_file_page()\n",
-			block, buf_get_state_name(block));
+		ib::error() << "Block:" << block
+			    << " incorrect state:" << buf_get_state_name(block)
+			    << " in buf_LRU_block_free_non_file_page";
 		return; /* Continue */
 	}
 
@@ -2280,27 +2281,27 @@ buf_LRU_block_remove_hashed(
 	}
 
 	hashed_bpage = buf_page_hash_get_low(buf_pool, bpage->id);
-
 	if (bpage != hashed_bpage) {
 		ib::error() << "Page " << bpage->id
 			<< " not found in the hash table";
 
 #ifdef UNIV_DEBUG
-		fprintf(stderr,
-			"InnoDB: in_page_hash %lu in_zip_hash %lu\n"
-			" in_free_list %lu in_flush_list %lu in_LRU_list %lu\n"
-			" zip.data %p zip_size %lu page_state %d\n",
-			bpage->in_page_hash, bpage->in_zip_hash,
-			bpage->in_free_list, bpage->in_flush_list,
-			bpage->in_LRU_list, bpage->zip.data,
-			bpage->size.logical(),
-			buf_page_get_state(bpage));
+
+		
+		ib::error()
+			<< "in_page_hash:" << bpage->in_page_hash
+			<< " in_zip_hash:" << bpage->in_zip_hash
+			//			<< " in_free_list:"<< bpage->in_fee_list
+			<< " in_flush_list:" << bpage->in_flush_list
+			<< " in_LRU_list:" << bpage->in_LRU_list
+			<< " zip.data:" << bpage->zip.data
+			<< " zip_size:" << bpage->size.logical()
+			<< " page_state:" << buf_page_get_state(bpage);
 #else
-		fprintf(stderr,
-			"InnoDB: zip.data %p zip_size %lu page_state %d\n",
-			bpage->zip.data,
-			bpage->size.logical(),
-			buf_page_get_state(bpage));
+		ib::error()
+			<< " zip.data:" << bpage->zip.data
+			<< " zip_size:" << bpage->size.logical()
+			<< " page_state:" << buf_page_get_state(bpage);
 #endif
 
 		if (hashed_bpage) {
@@ -2751,14 +2752,14 @@ buf_LRU_print_instance(
 		case BUF_BLOCK_FILE_PAGE:
 			frame = buf_block_get_frame((buf_block_t*) bpage);
 			fprintf(stderr, "\ntype %lu"
-				" index id " UINT32PF "\n",
+				" index id " IB_ID_FMT "\n",
 				(ulong) fil_page_get_type(frame),
 				btr_page_get_index_id(frame));
 			break;
 		case BUF_BLOCK_ZIP_PAGE:
 			frame = bpage->zip.data;
 			fprintf(stderr, "\ntype %lu size %lu"
-				" index id " UINT32PF "\n",
+				" index id " IB_ID_FMT "\n",
 				(ulong) fil_page_get_type(frame),
 				(ulong) bpage->size.physical(),
 				btr_page_get_index_id(frame));
diff --git a/storage/innobase/buf/buf0mtflu.cc b/storage/innobase/buf/buf0mtflu.cc
index 06aaac3..117de5c 100644
--- a/storage/innobase/buf/buf0mtflu.cc
+++ b/storage/innobase/buf/buf0mtflu.cc
@@ -350,7 +350,7 @@ DECLARE_THREAD(mtflush_io_thread)(
 		}
 	}
 
-	os_thread_exit(NULL);
+	os_thread_exit();
 	OS_THREAD_DUMMY_RETURN;
 }
 
diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc
index 5de0412..e96c61d 100644
--- a/storage/innobase/buf/buf0rea.cc
+++ b/storage/innobase/buf/buf0rea.cc
@@ -746,10 +746,10 @@ buf_read_ahead_linear(
 
 	if (count) {
 		DBUG_PRINT("ib_buf", ("linear read-ahead %lu pages, "
-				      UINT32PF ":" UINT32PF,
+				      "%lu:%lu",
 				      count,
-				      page_id.space(),
-				      page_id.page_no()));
+				      (ulint)page_id.space(),
+				      (ulint)page_id.page_no()));
 	}
 
 	/* Read ahead is considered one I/O operation for the purpose of
@@ -773,13 +773,6 @@ buf_read_ibuf_merge_pages(
 					to get read in, before this
 					function returns */
 	const ulint*	space_ids,	/*!< in: array of space ids */
-	const ib_uint64_t* space_versions,/*!< in: the spaces must have
-					this version number
-					(timestamp), otherwise we
-					discard the read; we use this
-					to cancel reads if DISCARD +
-					IMPORT may have changed the
-					tablespace size */
 	const ulint*	page_nos,	/*!< in: array of page numbers
 					to read, with the highest page
 					number the last in the
diff --git a/storage/innobase/data/data0data.cc b/storage/innobase/data/data0data.cc
index b4df869..4b788c8 100644
--- a/storage/innobase/data/data0data.cc
+++ b/storage/innobase/data/data0data.cc
@@ -447,7 +447,7 @@ dfield_print_also_hex(
 		fputs(" Hex: ",stderr);
 
 		for (i = 0; i < len; i++) {
-			fprintf(stderr, "%02lx", (ulint) *data++);
+			fprintf(stderr, "%02lx", static_cast<ulong>(*data++));
 		}
 
 		if (dfield_is_ext(dfield)) {
@@ -837,6 +837,7 @@ dfield_t::clone(
 	obj->ext  = ext;
 	obj->len  = len;
 	obj->type = type;
+	obj->spatial_status = spatial_status;
 
 	if (len != UNIV_SQL_NULL) {
 		obj->data = obj + 1;
diff --git a/storage/innobase/dict/dict0boot.cc b/storage/innobase/dict/dict0boot.cc
index 4ffcf64..5c4e204 100644
--- a/storage/innobase/dict/dict0boot.cc
+++ b/storage/innobase/dict/dict0boot.cc
@@ -516,9 +516,9 @@ dict_boot(void)
 			dict_load_sys_table(dict_sys->sys_indexes);
 			dict_load_sys_table(dict_sys->sys_fields);
 		}
+	}
 
 	mutex_exit(&dict_sys->mutex);
-	}
 
 	return(err);
 }
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index 5c7d41a..3195242 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -494,8 +494,11 @@ dict_build_tablespace_for_table(
 
 		/* Determine the tablespace flags. */
 		bool	is_temp = dict_table_is_temporary(table);
+		bool	is_encrypted = dict_table_is_encrypted(table);
 		bool	has_data_dir = DICT_TF_HAS_DATA_DIR(table->flags);
-		ulint	fsp_flags = dict_tf_to_fsp_flags(table->flags, is_temp);
+		ulint	fsp_flags = dict_tf_to_fsp_flags(table->flags,
+							 is_temp,
+							 is_encrypted);
 
 		/* Determine the full filepath */
 		if (is_temp) {
@@ -544,9 +547,14 @@ dict_build_tablespace_for_table(
 		mtr.set_named_space(table->space);
 		dict_disable_redo_if_temporary(table, &mtr);
 
-		fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
+		bool ret = fsp_header_init(table->space,
+					   FIL_IBD_FILE_INITIAL_SIZE,
+					   &mtr);
 
 		mtr_commit(&mtr);
+		if (!ret) {
+			return(DB_ERROR);
+		}
 	} else {
 		/* We do not need to build a tablespace for this table. It
 		is already built.  Just find the correct tablespace ID. */
@@ -2290,6 +2298,197 @@ dict_create_add_foreign_to_dictionary(
 	DBUG_RETURN(error);
 }
 
+/** Check whether a column is in an index by the column name
+ at param[in]	col_name	column name for the column to be checked
+ at param[in]	index		the index to be searched
+ at return	true if this column is in the index, otherwise, false */
+static
+bool
+dict_index_has_col_by_name(
+/*=======================*/
+	const char*		col_name,
+	const dict_index_t*	index)
+{
+	for (ulint i = 0; i < index->n_fields; i++) {
+		dict_field_t*   field = dict_index_get_nth_field(index, i);
+
+		if (strcmp(field->name, col_name) == 0) {
+			return(true);
+		}
+	}
+	return(false);
+}
+
+/** Check whether the foreign constraint could be on a column that is
+part of a virtual index (index contains virtual column) in the table
+ at param[in]	fk_col_name	FK column name to be checked
+ at param[in]	table		the table
+ at return	true if this column is indexed with other virtual columns */
+bool
+dict_foreign_has_col_in_v_index(
+	const char*		fk_col_name,
+	const dict_table_t*	table)
+{
+	/* virtual column can't be Primary Key, so start with secondary index */
+	for (dict_index_t* index = dict_table_get_next_index(
+		     dict_table_get_first_index(table));
+	     index;
+	     index = dict_table_get_next_index(index)) {
+
+		if (dict_index_has_virtual(index)) {
+			if (dict_index_has_col_by_name(fk_col_name, index)) {
+				return(true);
+			}
+		}
+	}
+
+	return(false);
+}
+
+
+/** Check whether the foreign constraint could be on a column that is
+a base column of some indexed virtual columns.
+ at param[in]	col_name	column name for the column to be checked
+ at param[in]	table		the table
+ at return	true if this column is a base column, otherwise, false */
+bool
+dict_foreign_has_col_as_base_col(
+	const char*		col_name,
+	const dict_table_t*	table)
+{
+	/* Loop through each virtual column and check if its base column has
+	the same name as the column name being checked */
+	for (ulint i = 0; i < table->n_v_cols; i++) {
+		dict_v_col_t*	v_col = dict_table_get_nth_v_col(table, i);
+
+		/* Only check if the virtual column is indexed */
+		if (!v_col->m_col.ord_part) {
+			continue;
+		}
+
+		for (ulint j = 0; j < v_col->num_base; j++) {
+			if (strcmp(col_name, dict_table_get_col_name(
+					   table,
+					   v_col->base_col[j]->ind)) == 0) {
+				return(true);
+			}
+		}
+	}
+
+	return(false);
+}
+
+/** Check if a foreign constraint is on the given column name.
+ at param[in]	col_name	column name to be searched for fk constraint
+ at param[in]	table		table to which foreign key constraint belongs
+ at return true if fk constraint is present on the table, false otherwise. */
+static
+bool
+dict_foreign_base_for_stored(
+	const char*		col_name,
+	const dict_table_t*	table)
+{
+	/* Loop through each stored column and check if its base column has
+	the same name as the column name being checked */
+	dict_s_col_list::const_iterator	it;
+	for (it = table->s_cols->begin();
+	     it != table->s_cols->end(); ++it) {
+		dict_s_col_t	s_col = *it;
+
+		for (ulint j = 0; j < s_col.num_base; j++) {
+			if (strcmp(col_name, dict_table_get_col_name(
+						table,
+						s_col.base_col[j]->ind)) == 0) {
+				return(true);
+			}
+		}
+	}
+
+	return(false);
+}
+
+/** Check if a foreign constraint is on columns served as base columns
+of any stored column. This is to prevent creating SET NULL or CASCADE
+constraint on such columns
+ at param[in]	local_fk_set	set of foreign key objects, to be added to
+the dictionary tables
+ at param[in]	table		table to which the foreign key objects in
+local_fk_set belong to
+ at return true if yes, otherwise, false */
+bool
+dict_foreigns_has_s_base_col(
+	const dict_foreign_set&	local_fk_set,
+	const dict_table_t*	table)
+{
+	dict_foreign_t*	foreign;
+
+	if (table->s_cols == NULL) {
+		return (false);
+	}
+
+	for (dict_foreign_set::const_iterator it = local_fk_set.begin();
+	     it != local_fk_set.end(); ++it) {
+
+		foreign = *it;
+		ulint	type = foreign->type;
+
+		type &= ~(DICT_FOREIGN_ON_DELETE_NO_ACTION
+			  | DICT_FOREIGN_ON_UPDATE_NO_ACTION);
+
+		if (type == 0) {
+			continue;
+		}
+
+		for (ulint i = 0; i < foreign->n_fields; i++) {
+			/* Check if the constraint is on a column that
+			is a base column of any stored column */
+			if (dict_foreign_base_for_stored(
+				foreign->foreign_col_names[i], table)) {
+				return(true);
+			}
+		}
+	}
+
+	return(false);
+}
+
+/** Check if a column is in foreign constraint with CASCADE properties or
+SET NULL
+ at param[in]	table		table
+ at param[in]	fk_col_name	name for the column to be checked
+ at return true if the column is in foreign constraint, otherwise, false */
+bool
+dict_foreigns_has_this_col(
+	const dict_table_t*	table,
+	const char*		col_name)
+{
+	dict_foreign_t*		foreign;
+	const dict_foreign_set*	local_fk_set = &table->foreign_set;
+
+	for (dict_foreign_set::const_iterator it = local_fk_set->begin();
+	     it != local_fk_set->end();
+	     ++it) {
+		foreign = *it;
+		ut_ad(foreign->id != NULL);
+		ulint	type = foreign->type;
+
+		type &= ~(DICT_FOREIGN_ON_DELETE_NO_ACTION
+			  | DICT_FOREIGN_ON_UPDATE_NO_ACTION);
+
+		if (type == 0) {
+			continue;
+		}
+
+		for (ulint i = 0; i < foreign->n_fields; i++) {
+			if (strcmp(foreign->foreign_col_names[i],
+				   col_name) == 0) {
+				return(true);
+			}
+		}
+	}
+	return(false);
+}
+
 /** Adds the given set of foreign key objects to the dictionary tables
 in the database. This function does not modify the dictionary cache. The
 caller must ensure that all foreign key objects contain a valid constraint
diff --git a/storage/innobase/dict/dict0defrag_bg.cc b/storage/innobase/dict/dict0defrag_bg.cc
new file mode 100644
index 0000000..82aa3ab
--- /dev/null
+++ b/storage/innobase/dict/dict0defrag_bg.cc
@@ -0,0 +1,403 @@
+/*****************************************************************************
+
+Copyright (c) 2016, 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
+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, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+ at file dict/dict0defrag_bg.cc
+Defragmentation routines.
+
+Created 25/08/2016 Jan Lindström
+*******************************************************/
+
+#include "dict0dict.h"
+#include "dict0stats.h"
+#include "dict0stats_bg.h"
+#include "dict0defrag_bg.h"
+#include "row0mysql.h"
+#include "srv0start.h"
+#include "ut0new.h"
+
+#ifdef UNIV_NONINL
+# include "dict0stats_bg.ic"
+#endif
+
+#include <vector>
+
+static ib_mutex_t		defrag_pool_mutex;
+
+#ifdef MYSQL_PFS
+static mysql_pfs_key_t		defrag_pool_mutex_key;
+#endif
+
+/** The number of tables that can be added to "defrag_pool" before
+it is enlarged */
+static const ulint		DEFRAG_POOL_INITIAL_SLOTS = 128;
+
+/** Indices whose defrag stats need to be saved to persistent storage.*/
+struct defrag_pool_item_t {
+	table_id_t	table_id;
+	index_id_t	index_id;
+};
+
+/** Allocator type, used by std::vector */
+typedef ut_allocator<defrag_pool_item_t>
+	defrag_pool_allocator_t;
+
+/** The multitude of tables to be defragmented- an STL vector */
+typedef std::vector<defrag_pool_item_t, defrag_pool_allocator_t>
+	defrag_pool_t;
+
+/** Iterator type for iterating over the elements of objects of type
+defrag_pool_t. */
+typedef defrag_pool_t::iterator		defrag_pool_iterator_t;
+
+/** Pool where we store information on which tables are to be processed
+by background defragmentation. */
+static defrag_pool_t*			defrag_pool;
+
+extern bool dict_stats_start_shutdown;
+
+/*****************************************************************//**
+Initialize the defrag pool, called once during thread initialization. */
+void
+dict_defrag_pool_init(void)
+/*=======================*/
+{
+	ut_ad(!srv_read_only_mode);
+	/* JAN: TODO: MySQL 5.7 PSI
+	const PSI_memory_key	key2 = mem_key_dict_defrag_pool_t;
+
+	defrag_pool = UT_NEW(defrag_pool_t(defrag_pool_allocator_t(key2)), key2);
+
+	recalc_pool->reserve(RECALC_POOL_INITIAL_SLOTS);
+	*/
+	defrag_pool = new std::vector<defrag_pool_item_t, defrag_pool_allocator_t>();
+
+	/* We choose SYNC_STATS_DEFRAG to be below SYNC_FSP_PAGE. */
+	mutex_create(LATCH_ID_DEFRAGMENT_MUTEX, &defrag_pool_mutex);
+}
+
+/*****************************************************************//**
+Free the resources occupied by the defrag pool, called once during
+thread de-initialization. */
+void
+dict_defrag_pool_deinit(void)
+/*=========================*/
+{
+	ut_ad(!srv_read_only_mode);
+
+	defrag_pool->clear();
+	mutex_free(&defrag_pool_mutex);
+
+	UT_DELETE(defrag_pool);
+}
+
+/*****************************************************************//**
+Get an index from the auto defrag pool. The returned index id is removed
+from the pool.
+ at return true if the pool was non-empty and "id" was set, false otherwise */
+static
+bool
+dict_stats_defrag_pool_get(
+/*=======================*/
+	table_id_t*	table_id,	/*!< out: table id, or unmodified if
+					list is empty */
+	index_id_t*	index_id)	/*!< out: index id, or unmodified if
+					list is empty */
+{
+	ut_ad(!srv_read_only_mode);
+
+	mutex_enter(&defrag_pool_mutex);
+
+	if (defrag_pool->empty()) {
+		mutex_exit(&defrag_pool_mutex);
+		return(false);
+	}
+
+	defrag_pool_item_t& item = defrag_pool->back();
+	*table_id = item.table_id;
+	*index_id = item.index_id;
+
+	defrag_pool->pop_back();
+
+	mutex_exit(&defrag_pool_mutex);
+
+	return(true);
+}
+
+/*****************************************************************//**
+Add an index in a table to the defrag pool, which is processed by the
+background stats gathering thread. Only the table id and index id are
+added to the list, so the table can be closed after being enqueued and
+it will be opened when needed. If the table or index does not exist later
+(has been DROPped), then it will be removed from the pool and skipped. */
+void
+dict_stats_defrag_pool_add(
+/*=======================*/
+	const dict_index_t*	index)	/*!< in: table to add */
+{
+	defrag_pool_item_t item;
+
+	ut_ad(!srv_read_only_mode);
+
+	mutex_enter(&defrag_pool_mutex);
+
+	/* quit if already in the list */
+	for (defrag_pool_iterator_t iter = defrag_pool->begin();
+	     iter != defrag_pool->end();
+	     ++iter) {
+		if ((*iter).table_id == index->table->id
+		    && (*iter).index_id == index->id) {
+			mutex_exit(&defrag_pool_mutex);
+			return;
+		}
+	}
+
+	item.table_id = index->table->id;
+	item.index_id = index->id;
+	defrag_pool->push_back(item);
+
+	mutex_exit(&defrag_pool_mutex);
+
+	os_event_set(dict_stats_event);
+}
+
+/*****************************************************************//**
+Delete a given index from the auto defrag pool. */
+void
+dict_stats_defrag_pool_del(
+/*=======================*/
+	const dict_table_t*	table,	/*!<in: if given, remove
+					all entries for the table */
+	const dict_index_t*	index)	/*!< in: if given, remove this index */
+{
+	ut_a((table && !index) || (!table && index));
+	ut_ad(!srv_read_only_mode);
+	ut_ad(mutex_own(&dict_sys->mutex));
+
+	mutex_enter(&defrag_pool_mutex);
+
+	defrag_pool_iterator_t iter = defrag_pool->begin();
+	while (iter != defrag_pool->end()) {
+		if ((table && (*iter).table_id == table->id)
+		    || (index
+			&& (*iter).table_id == index->table->id
+			&& (*iter).index_id == index->id)) {
+			/* erase() invalidates the iterator */
+			iter = defrag_pool->erase(iter);
+			if (index)
+				break;
+		} else {
+			iter++;
+		}
+	}
+
+	mutex_exit(&defrag_pool_mutex);
+}
+
+/*****************************************************************//**
+Get the first index that has been added for updating persistent defrag
+stats and eventually save its stats. */
+static
+void
+dict_stats_process_entry_from_defrag_pool()
+/*=======================================*/
+{
+	table_id_t	table_id;
+	index_id_t	index_id;
+	dberr_t		err = DB_SUCCESS;
+
+	ut_ad(!srv_read_only_mode);
+
+	/* pop the first index from the auto defrag pool */
+	if (!dict_stats_defrag_pool_get(&table_id, &index_id)) {
+		/* no index in defrag pool */
+		return;
+	}
+
+	dict_table_t*	table;
+
+	mutex_enter(&dict_sys->mutex);
+
+	/* If the table is no longer cached, we've already lost the in
+	memory stats so there's nothing really to write to disk. */
+	table = dict_table_open_on_id(table_id, TRUE,
+				      DICT_TABLE_OP_OPEN_ONLY_IF_CACHED);
+
+	if (table == NULL) {
+		mutex_exit(&dict_sys->mutex);
+		return;
+	}
+
+	/* Check whether table is corrupted */
+	if (table->corrupted) {
+		dict_table_close(table, TRUE, FALSE);
+		mutex_exit(&dict_sys->mutex);
+		return;
+	}
+	mutex_exit(&dict_sys->mutex);
+
+	dict_index_t*	index = dict_table_find_index_on_id(table, index_id);
+
+	if (index == NULL) {
+		return;
+	}
+
+	/* Check whether index is corrupted */
+	if (dict_index_is_corrupted(index)) {
+		dict_table_close(table, FALSE, FALSE);
+		return;
+	}
+
+	err = dict_stats_save_defrag_stats(index);
+
+	if (err != DB_SUCCESS) {
+		ib::error() << "Saving defragmentation status for table "
+			    << index->table->name.m_name
+			    << " index " << index->name()
+			    << " failed " << err;
+	}
+
+	dict_table_close(table, FALSE, FALSE);
+}
+
+/*****************************************************************//**
+Get the first index that has been added for updating persistent defrag
+stats and eventually save its stats. */
+void
+dict_defrag_process_entries_from_defrag_pool()
+/*==========================================*/
+{
+	while (defrag_pool->size() && !dict_stats_start_shutdown) {
+		dict_stats_process_entry_from_defrag_pool();
+	}
+}
+
+/*********************************************************************//**
+Save defragmentation result.
+ at return DB_SUCCESS or error code */
+dberr_t
+dict_stats_save_defrag_summary(
+/*============================*/
+	dict_index_t*	index)	/*!< in: index */
+{
+	dberr_t	ret=DB_SUCCESS;
+	lint	now = (lint) ut_time();
+
+	if (dict_index_is_univ(index)) {
+		return DB_SUCCESS;
+	}
+
+	rw_lock_x_lock(dict_operation_lock);
+	mutex_enter(&dict_sys->mutex);
+
+	ret = dict_stats_save_index_stat(index, now, "n_pages_freed",
+					 index->stat_defrag_n_pages_freed,
+					 NULL,
+					 "Number of pages freed during"
+					 " last defragmentation run.",
+					 NULL);
+
+	mutex_exit(&dict_sys->mutex);
+	rw_lock_x_unlock(dict_operation_lock);
+
+	return (ret);
+}
+
+/*********************************************************************//**
+Save defragmentation stats for a given index.
+ at return DB_SUCCESS or error code */
+dberr_t
+dict_stats_save_defrag_stats(
+/*============================*/
+	dict_index_t*	index)	/*!< in: index */
+{
+	dberr_t	ret;
+
+	if (index->table->ibd_file_missing) {
+		ut_print_timestamp(stderr);
+		fprintf(stderr,
+			" InnoDB: Cannot save defragment stats because "
+			".ibd file is missing.\n");
+		return (DB_TABLESPACE_DELETED);
+	}
+	if (dict_index_is_corrupted(index)) {
+		ut_print_timestamp(stderr);
+		fprintf(stderr,
+			" InnoDB: Cannot save defragment stats because "
+			"index is corrupted.\n");
+		return(DB_CORRUPTION);
+	}
+
+	if (dict_index_is_univ(index)) {
+		return DB_SUCCESS;
+	}
+
+	lint	now = (lint) ut_time();
+	mtr_t	mtr;
+	ulint	n_leaf_pages;
+	ulint	n_leaf_reserved;
+	mtr_start(&mtr);
+	mtr_s_lock(dict_index_get_lock(index), &mtr);
+	n_leaf_reserved = btr_get_size_and_reserved(index, BTR_N_LEAF_PAGES,
+						    &n_leaf_pages, &mtr);
+	mtr_commit(&mtr);
+
+	if (n_leaf_reserved == ULINT_UNDEFINED) {
+		// The index name is different during fast index creation,
+		// so the stats won't be associated with the right index
+		// for later use. We just return without saving.
+		return DB_SUCCESS;
+	}
+
+	rw_lock_x_lock(dict_operation_lock);
+
+	mutex_enter(&dict_sys->mutex);
+	ret = dict_stats_save_index_stat(index, now, "n_page_split",
+					 index->stat_defrag_n_page_split,
+					 NULL,
+					 "Number of new page splits on leaves"
+					 " since last defragmentation.",
+					 NULL);
+	if (ret != DB_SUCCESS) {
+		goto end;
+	}
+
+	ret = dict_stats_save_index_stat(
+		index, now, "n_leaf_pages_defrag",
+		n_leaf_pages,
+		NULL,
+		"Number of leaf pages when this stat is saved to disk",
+		NULL);
+	if (ret != DB_SUCCESS) {
+		goto end;
+	}
+
+	ret = dict_stats_save_index_stat(
+		index, now, "n_leaf_pages_reserved",
+		n_leaf_reserved,
+		NULL,
+		"Number of pages reserved for this index leaves when this stat "
+		"is saved to disk",
+		NULL);
+
+end:
+	mutex_exit(&dict_sys->mutex);
+	rw_lock_x_unlock(dict_operation_lock);
+
+	return (ret);
+}
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 687353c..6a33de6 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -25,6 +25,9 @@ Data dictionary system
 Created 1/8/1996 Heikki Tuuri
 ***********************************************************************/
 
+#include <my_config.h>
+#include <string>
+
 #include "ha_prototypes.h"
 #include <mysqld.h>
 #include <strfunc.h>
@@ -33,7 +36,6 @@ Created 1/8/1996 Heikki Tuuri
 #include "fts0fts.h"
 #include "fil0fil.h"
 #include <algorithm>
-#include <string>
 
 #ifdef UNIV_NONINL
 #include "dict0dict.ic"
@@ -569,6 +571,8 @@ dict_table_close_and_drop(
 	trx_t*		trx,		/*!< in: data dictionary transaction */
 	dict_table_t*	table)		/*!< in/out: table */
 {
+	dberr_t err = DB_SUCCESS;
+
 	ut_ad(mutex_own(&dict_sys->mutex));
 	ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
 	ut_ad(trx->dict_operation != TRX_DICT_OP_NONE);
@@ -583,7 +587,13 @@ dict_table_close_and_drop(
 	ut_a(!table->stat_initialized);
 #endif /* UNIV_DEBUG || UNIV_DDL_DEBUG */
 
-	row_merge_drop_table(trx, table);
+	err = row_merge_drop_table(trx, table);
+
+	if (err != DB_SUCCESS) {
+		ib::error() << "At " << __FILE__ << ":" << __LINE__
+			    << " row_merge_drop_table returned error: " << err
+			    << " table: " << table->name.m_name;
+	}
 }
 
 /** Check if the table has a given (non_virtual) column.
@@ -684,6 +694,7 @@ dict_table_get_col_name_for_mysql(
 
 	return(s);
 }
+
 /** Returns a virtual column's name.
 @param[in]	table	target table
 @param[in]	col_nr	virtual column number (nth virtual column)
@@ -1237,7 +1248,7 @@ dict_init(void)
 		       dict_operation_lock, SYNC_DICT_OPERATION);
 
 	if (!srv_read_only_mode) {
-		dict_foreign_err_file = os_file_create_tmpfile();
+		dict_foreign_err_file = os_file_create_tmpfile(NULL);
 		ut_a(dict_foreign_err_file);
 	}
 
@@ -1309,9 +1320,7 @@ dict_table_open_on_name(
 		if (ignore_err == DICT_ERR_IGNORE_NONE
 			&& table->is_encrypted) {
 			/* Make life easy for drop table. */
-			if (table->can_be_evicted) {
-				dict_table_move_from_lru_to_non_lru(table);
-			}
+			dict_table_prevent_eviction(table);
 
 			if (table->can_be_evicted) {
 				dict_move_to_mru(table);
@@ -1328,10 +1337,8 @@ dict_table_open_on_name(
 		/* If table is corrupted, return NULL */
 		else if (ignore_err == DICT_ERR_IGNORE_NONE
 		    && table->corrupted) {
-
 			/* Make life easy for drop table. */
 			dict_table_prevent_eviction(table);
-
 			if (!dict_locked) {
 				mutex_exit(&dict_sys->mutex);
 			}
@@ -1668,7 +1675,6 @@ dict_table_move_from_lru_to_non_lru(
 @param[in]	table	table instance
 @param[in]	id	index id
 @return index or NULL */
-UNIV_INTERN
 dict_index_t*
 dict_table_find_index_on_id(
 	const dict_table_t*	table,
@@ -1764,6 +1770,7 @@ dict_table_rename_in_cache(
 	dict_index_t*	index;
 	ulint		fold;
 	char		old_name[MAX_FULL_NAME_LEN + 1];
+	os_file_type_t	ftype;
 
 	ut_ad(mutex_own(&dict_sys->mutex));
 
@@ -1798,7 +1805,6 @@ dict_table_rename_in_cache(
 	.ibd file and rebuild the .isl file if needed. */
 
 	if (dict_table_is_discarded(table)) {
-		os_file_type_t	type;
 		bool		exists;
 		char*		filepath;
 
@@ -1826,7 +1832,7 @@ dict_table_rename_in_cache(
 		fil_delete_tablespace(table->space, BUF_REMOVE_ALL_NO_WRITE);
 
 		/* Delete any temp file hanging around. */
-		if (os_file_status(filepath, &exists, &type)
+		if (os_file_status(filepath, &exists, &ftype)
 		    && exists
 		    && !os_file_delete_if_exists(innodb_temp_file_key,
 						 filepath, NULL)) {
@@ -1860,19 +1866,31 @@ dict_table_rename_in_cache(
 				ut_free(old_path);
 				return(DB_TABLESPACE_EXISTS);
 			}
+		} else {
+			new_path = fil_make_filepath(
+				NULL, new_name, IBD, false);
+		}
+
+		/* New filepath must not exist. */
+		err = fil_rename_tablespace_check(
+			table->space, old_path, new_path, false);
+		if (err != DB_SUCCESS) {
+			ut_free(old_path);
+			ut_free(new_path);
+			return(err);
 		}
 
 		bool	success = fil_rename_tablespace(
 			table->space, old_path, new_name, new_path);
 
 		ut_free(old_path);
+		ut_free(new_path);
 
 		/* If the tablespace is remote, a new .isl file was created
-		If success, delete the old one. If not, delete the new one.  */
-		if (new_path) {
-
-			ut_free(new_path);
-			RemoteDatafile::delete_link_file(success ? old_name : new_name);
+		If success, delete the old one. If not, delete the new one. */
+		if (DICT_TF_HAS_DATA_DIR(table->flags)) {
+			RemoteDatafile::delete_link_file(
+				success ? old_name : new_name);
 		}
 
 		if (!success) {
@@ -2271,6 +2289,12 @@ dict_table_remove_from_cache_low(
 		trx_free_for_background(trx);
 	}
 
+	/* Free virtual column template if any */
+	if (table->vc_templ != NULL) {
+		dict_free_vc_templ(table->vc_templ);
+		UT_DELETE(table->vc_templ);
+	}
+
 	size = mem_heap_get_size(table->heap) + strlen(table->name.m_name) + 1;
 
 	ut_ad(dict_sys->size >= size);
@@ -2516,7 +2540,7 @@ dict_index_too_big_for_tree(
 		REC_STATUS_ORDINARY records. */
 
 		field_max_size = dict_col_get_fixed_size(col, comp);
-		if (field_max_size) {
+		if (field_max_size && field->fixed_len != 0) {
 			/* dict_index_add_col() should guarantee this */
 			ut_ad(!field->prefix_len
 			      || field->fixed_len == field->prefix_len);
@@ -2681,18 +2705,31 @@ dict_index_add_to_cache_w_vcol(
 	}
 
 	n_ord = new_index->n_uniq;
-
 	/* Flag the ordering columns and also set column max_prefix */
 
 	for (i = 0; i < n_ord; i++) {
 		const dict_field_t*	field
 			= dict_index_get_nth_field(new_index, i);
 
-		field->col->ord_part = 1;
-
-		if (field->prefix_len > field->col->max_prefix) {
+		/* Check the column being added in the index for
+		the first time and flag the ordering column. */
+		if (field->col->ord_part == 0 ) {
+			field->col->max_prefix = field->prefix_len;
+			field->col->ord_part = 1;
+		} else if (field->prefix_len == 0) {
+			/* Set the max_prefix for a column to 0 if
+			its prefix length is 0 (for this index)
+			even if it was a part of any other index
+			with some prefix length. */
+			field->col->max_prefix = 0;
+		} else if (field->col->max_prefix != 0
+			   && field->prefix_len
+			   > field->col->max_prefix) {
+			/* Set the max_prefix value based on the
+			prefix_len. */
 			field->col->max_prefix = field->prefix_len;
 		}
+		ut_ad(field->col->ord_part == 1);
 	}
 
 	new_index->stat_n_diff_key_vals =
@@ -3051,7 +3088,6 @@ dict_index_add_col(
 	field = dict_index_get_nth_field(index, index->n_def - 1);
 
 	field->col = col;
-
 	/* DATA_POINT is a special type, whose fixed_len should be:
 	1) DATA_MBR_LEN, when it's indexed in R-TREE. In this case,
 	it must be the first col to be added.
@@ -3663,7 +3699,7 @@ dict_foreign_find_index(
 					/*!< out: column number where
 					error happened */
 	dict_index_t**		err_index)
-			                /*!< out: index where error
+					/*!< out: index where error
 					happened */
 {
 	dict_index_t*	index;
@@ -4645,6 +4681,11 @@ dict_foreign_push_index_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 be
+accompanied with indexes in bot participating tables. The indexes are allowed
+to contain more fields than mentioned in the constraint.
 @return error code or DB_SUCCESS */
 static
 dberr_t
@@ -4879,6 +4920,10 @@ dict_create_foreign_constraints_low(
 			return(DB_CANNOT_ADD_CONSTRAINT);
 		}
 
+		if (dict_foreigns_has_s_base_col(local_fk_set, table)) {
+			return(DB_NO_FK_ON_S_BASE_COL);
+		}
+
 		/**********************************************************/
 		/* The following call adds the foreign key constraints
 		to the data dictionary system tables on disk */
@@ -4894,6 +4939,8 @@ dict_create_foreign_constraints_low(
 				      local_fk_set.end(),
 				      dict_foreign_add_to_referenced_table());
 			local_fk_set.clear();
+
+			dict_mem_table_fill_foreign_vcol_set(table);
 		}
 		return(error);
 	}
@@ -4919,53 +4966,52 @@ dict_create_foreign_constraints_low(
 	}
 
 	if (my_isspace(cs, *ptr)) {
-                ptr1 = dict_accept(cs, ptr, "IF", &success);
+		ptr1 = dict_accept(cs, ptr, "IF", &success);
 
-                if (success) {
-                        if (!my_isspace(cs, *ptr1)) {
-                                goto loop;
-                        }
-                        ptr1 = dict_accept(cs, ptr1, "NOT", &success);
-                        if (!success) {
-                                goto loop;
-                        }
-                        ptr1 = dict_accept(cs, ptr1, "EXISTS", &success);
-                        if (!success) {
-                                goto loop;
-                        }
-                        ptr = ptr1;
-                }
+		if (success) {
+			if (!my_isspace(cs, *ptr1)) {
+				goto loop;
+			}
+			ptr1 = dict_accept(cs, ptr1, "NOT", &success);
+			if (!success) {
+				goto loop;
+			}
+			ptr1 = dict_accept(cs, ptr1, "EXISTS", &success);
+			if (!success) {
+				goto loop;
+			}
+			ptr = ptr1;
+		}
 	}
 
 	orig = ptr;
 	ptr = dict_accept(cs, ptr, "(", &success);
 
 	if (!success) {
-                if (constraint_name) {
-		  /* MySQL allows also an index id before the '('; we
-		  skip it */
-		  ptr = dict_skip_word(cs, ptr, &success);
-		  if (!success) {
-			  dict_foreign_report_syntax_err(
-				"%s table %s with foreign key constraint"
-				" failed. Parse error in '%s'"
-				" near '%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. Parse error in '%s'"
-				" near '%s'.",
-				operation, create_name, start_of_latest_foreign, orig);
-			  return(DB_CANNOT_ADD_CONSTRAINT);
-                  }
-		}
-                else {
-		  while (my_isspace(cs, *ptr)) {
-			  ptr++;
-		  }
+		if (constraint_name) {
+			/* MySQL allows also an index id before the '('; we
+			skip it */
+			ptr = dict_skip_word(cs, ptr, &success);
+			if (!success) {
+				dict_foreign_report_syntax_err(
+					"%s table %s with foreign key constraint"
+					" failed. Parse error in '%s'"
+					" near '%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. Parse error in '%s'"
+					" near '%s'.",
+					operation, create_name, start_of_latest_foreign, orig);
+				return(DB_CANNOT_ADD_CONSTRAINT);
+			}
+		} else {
+			while (my_isspace(cs, *ptr)) {
+				ptr++;
+			}
 
-		  ptr = dict_scan_id(cs, ptr, heap,
+			ptr = dict_scan_id(cs, ptr, heap,
 				     &constraint_name, FALSE, FALSE);
 		}
 
@@ -5095,6 +5141,23 @@ dict_create_foreign_constraints_low(
 		return(DB_CANNOT_ADD_CONSTRAINT);
 	}
 
+	/* Don't allow foreign keys on partitioned tables yet. */
+	ptr1 = dict_scan_to(ptr, "PARTITION");
+	if (ptr1) {
+		ptr1 = dict_accept(cs, ptr1, "PARTITION", &success);
+		if (success && my_isspace(cs, *ptr1)) {
+			ptr2 = dict_accept(cs, ptr1, "BY", &success);
+			if (success) {
+				my_error(ER_FOREIGN_KEY_ON_PARTITIONED,MYF(0));
+				return(DB_CANNOT_ADD_CONSTRAINT);
+			}
+		}
+	}
+	if (dict_table_is_partition(table)) {
+		my_error(ER_FOREIGN_KEY_ON_PARTITIONED,MYF(0));
+		return(DB_CANNOT_ADD_CONSTRAINT);
+	}
+
 	/* Let us create a constraint struct */
 
 	foreign = dict_mem_foreign_create();
@@ -5602,7 +5665,7 @@ dict_foreign_parse_drop_constraints(
 	char*			str;
 	size_t			len;
 	const char*		ptr;
-        const char*             ptr1;
+	const char*		ptr1;
 	const char*		id;
 	CHARSET_INFO*		cs;
 
@@ -5656,11 +5719,10 @@ dict_foreign_parse_drop_constraints(
 	ptr1 = dict_accept(cs, ptr, "IF", &success);
 
 	if (success && my_isspace(cs, *ptr1)) {
-	        ptr1 = dict_accept(cs, ptr1, "EXISTS", &success);
-	        if (success) {
-
-                        ptr = ptr1;
-	        }
+		ptr1 = dict_accept(cs, ptr1, "EXISTS", &success);
+		if (success) {
+			ptr = ptr1;
+		}
 	}
 
 	ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
@@ -5875,6 +5937,12 @@ dict_index_copy_rec_order_prefix(
 			n = dict_index_get_n_unique_in_tree(index);
 		} else {
 			n = dict_index_get_n_unique_in_tree_nonleaf(index);
+			/* For internal node of R-tree, since we need to
+			compare the page no field, so, we need to copy this
+			field as well. */
+			if (dict_index_is_spatial(index)) {
+				n++;
+			}
 		}
 	}
 
@@ -5992,11 +6060,11 @@ dict_print_info_on_foreign_key_in_create_format(
 
 	str.append(" CONSTRAINT ");
 
-	str.append(ut_get_name(trx, FALSE, stripped_id));
+	str.append(innobase_quote_identifier(trx, stripped_id));
 	str.append(" FOREIGN KEY (");
 
 	for (i = 0;;) {
-		str.append(ut_get_name(trx, FALSE, foreign->foreign_col_names[i]));
+		str.append(innobase_quote_identifier(trx, foreign->foreign_col_names[i]));
 
 		if (++i < foreign->n_fields) {
 			str.append(", ");
@@ -6010,18 +6078,18 @@ dict_print_info_on_foreign_key_in_create_format(
 	if (dict_tables_have_same_db(foreign->foreign_table_name_lookup,
 				     foreign->referenced_table_name_lookup)) {
 		/* Do not print the database name of the referenced table */
-		str.append(ut_get_name(trx, TRUE,
+		str.append(ut_get_name(trx,
 			      dict_remove_db_name(
 				      foreign->referenced_table_name)));
 	} else {
-		str.append(ut_get_name(trx, TRUE,
+		str.append(ut_get_name(trx,
 				foreign->referenced_table_name));
 	}
 
 	str.append(" (");
 
 	for (i = 0;;) {
-		str.append(ut_get_name(trx, FALSE,
+		str.append(innobase_quote_identifier(trx,
 				foreign->referenced_col_names[i]));
 
 		if (++i < foreign->n_fields) {
@@ -6096,12 +6164,12 @@ dict_print_info_on_foreign_keys(
 					str.append(" ");
 				}
 
-				str.append(ut_get_name(trx, FALSE,
+				str.append(innobase_quote_identifier(trx,
 						foreign->foreign_col_names[i]));
 			}
 
 			str.append(") REFER ");
-			str.append(ut_get_name(trx, TRUE,
+			str.append(ut_get_name(trx,
 					foreign->referenced_table_name));
 			str.append(")");
 
@@ -6109,8 +6177,8 @@ dict_print_info_on_foreign_keys(
 				if (i) {
 					str.append(" ");
 				}
-				str.append(ut_get_name(
-						trx, FALSE,
+				str.append(innobase_quote_identifier(
+						trx,
 						foreign->referenced_col_names[i]));
 			}
 
@@ -6143,7 +6211,6 @@ dict_print_info_on_foreign_keys(
 	}
 
 	mutex_exit(&dict_sys->mutex);
-
 	return str;
 }
 
@@ -6262,6 +6329,13 @@ dict_set_corrupted(
 		goto func_exit;
 	}
 
+	/* If this is read only mode, do not update SYS_INDEXES, just
+	mark it as corrupted in memory */
+	if (srv_read_only_mode) {
+		index->type |= DICT_CORRUPT;
+		goto func_exit;
+	}
+
 	heap = mem_heap_create(sizeof(dtuple_t) + 2 * (sizeof(dfield_t)
 			       + sizeof(que_fork_t) + sizeof(upd_node_t)
 			       + sizeof(upd_t) + 12));
@@ -6451,6 +6525,7 @@ dict_set_merge_threshold_all_debug(
 
 	mutex_exit(&dict_sys->mutex);
 }
+
 #endif /* UNIV_DEBUG */
 #endif /* !UNIV_HOTBACKUP */
 
@@ -6914,7 +6989,8 @@ dict_fs2utf8(
 
 	errors = 0;
 	strconvert(
-                &my_charset_filename, buf, (uint) (buf_p - buf), system_charset_info,
+		&my_charset_filename, buf, (uint) (buf_p - buf),
+		system_charset_info,
 		table_utf8, table_utf8_size,
 		&errors);
 
@@ -7380,11 +7456,13 @@ dict_table_t::flags |     0     |    1    |     1      |    1
 fil_space_t::flags  |     0     |    0    |     1      |    1
 @param[in]	table_flags	dict_table_t::flags
 @param[in]	is_temp		whether the tablespace is temporary
+ at param[in]	is_encrypted	whether the tablespace is encrypted
 @return tablespace flags (fil_space_t::flags) */
 ulint
 dict_tf_to_fsp_flags(
 	ulint	table_flags,
-	bool	is_temp)
+	bool	is_temp,
+	bool	is_encrypted)
 {
 	DBUG_EXECUTE_IF("dict_tf_to_fsp_flags_failure",
 			return(ULINT_UNDEFINED););
@@ -7411,9 +7489,30 @@ dict_tf_to_fsp_flags(
 						   has_data_dir,
 						   is_shared,
 						   is_temp,
-						   page_compression,
-						   page_compression_level,
-						   atomic_writes);
+						   0,
+						   0,
+						   0,
+						   is_encrypted);
+
+	/* In addition, tablespace flags also contain if the page
+	compression is used for this table. */
+	if (page_compression) {
+		fsp_flags |= FSP_FLAGS_SET_PAGE_COMPRESSION(fsp_flags, page_compression);
+	}
+
+	/* In addition, tablespace flags also contain page compression level
+	if page compression is used for this table. */
+	if (page_compression && page_compression_level) {
+		fsp_flags |= FSP_FLAGS_SET_PAGE_COMPRESSION_LEVEL(fsp_flags, page_compression_level);
+	}
+
+	/* In addition, tablespace flags also contain flag if atomic writes
+	is used for this table */
+	if (atomic_writes) {
+		fsp_flags |= FSP_FLAGS_SET_ATOMIC_WRITES(fsp_flags, atomic_writes);
+	}
+
+	ut_ad(fsp_flags_is_valid(fsp_flags));
 
 	return(fsp_flags);
 }
@@ -7442,10 +7541,10 @@ dict_tf_to_row_format_string(
 }
 
 /** Look for any dictionary objects that are found in the given tablespace.
- at param[in]	space	Tablespace ID to search for.
+ at param[in]	space_id	Tablespace ID to search for.
 @return true if tablespace is empty. */
 bool
-dict_tablespace_is_empty(
+dict_space_is_empty(
 	ulint	space_id)
 {
 	btr_pcur_t	pcur;
@@ -7480,6 +7579,55 @@ dict_tablespace_is_empty(
 
 	return(!found);
 }
+
+/** Find the space_id for the given name in sys_tablespaces.
+ at param[in]	name	Tablespace name to search for.
+ at return the tablespace ID. */
+ulint
+dict_space_get_id(
+	const char*	name)
+{
+	btr_pcur_t	pcur;
+	const rec_t*	rec;
+	mtr_t		mtr;
+	ulint		name_len = strlen(name);
+	ulint		id = ULINT_UNDEFINED;
+
+	rw_lock_x_lock(dict_operation_lock);
+	mutex_enter(&dict_sys->mutex);
+	mtr_start(&mtr);
+
+	for (rec = dict_startscan_system(&pcur, &mtr, SYS_TABLESPACES);
+	     rec != NULL;
+	     rec = dict_getnext_system(&pcur, &mtr)) {
+		const byte*	field;
+		ulint		len;
+
+		field = rec_get_nth_field_old(
+			rec, DICT_FLD__SYS_TABLESPACES__NAME, &len);
+		ut_ad(len > 0);
+		ut_ad(len < OS_FILE_MAX_PATH);
+
+		if (len == name_len && ut_memcmp(name, field, len) == 0) {
+
+			field = rec_get_nth_field_old(
+				rec, DICT_FLD__SYS_TABLESPACES__SPACE, &len);
+			ut_ad(len == 4);
+			id = mach_read_from_4(field);
+
+			/* This is normally called by dict_getnext_system()
+			at the end of the index. */
+			btr_pcur_close(&pcur);
+			break;
+		}
+	}
+
+	mtr_commit(&mtr);
+	mutex_exit(&dict_sys->mutex);
+	rw_lock_x_unlock(dict_operation_lock);
+
+	return(id);
+}
 #endif /* !UNIV_HOTBACKUP */
 
 /** Determine the extent size (in pages) for the given table
diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc
index 5267cf1..f38ad85 100644
--- a/storage/innobase/dict/dict0load.cc
+++ b/storage/innobase/dict/dict0load.cc
@@ -733,7 +733,6 @@ dict_process_sys_datafiles(
 @param[in]	space_id	Tablespace ID
 @return First filepath (caller must invoke ut_free() on it)
 @retval NULL if no SYS_DATAFILES entry was found. */
-static
 char*
 dict_get_first_path(
 	ulint	space_id)
@@ -819,7 +818,7 @@ dict_get_first_path(
 @retval NULL if no dictionary entry was found. */
 static
 char*
-dict_get_space_name(
+dict_space_get_name(
 	ulint		space_id,
 	mem_heap_t*	callers_heap)
 {
@@ -1127,7 +1126,7 @@ dict_sys_tablespaces_rec_read(
 		rec, DICT_FLD__SYS_TABLESPACES__NAME, &len);
 	if (len == 0 || len == UNIV_SQL_NULL) {
 		ib::error() << "Wrong field length in SYS_TABLESPACES.NAME: "
-		<< len;
+			<< len;
 		return(false);
 	}
 	strncpy(name, reinterpret_cast<const char*>(field), NAME_LEN);
@@ -1137,7 +1136,7 @@ dict_sys_tablespaces_rec_read(
 		rec, DICT_FLD__SYS_TABLESPACES__FLAGS, &len);
 	if (len != 4) {
 		ib::error() << "Wrong field length in SYS_TABLESPACES.FLAGS: "
-		<< len;
+			<< len;
 		return(false);
 	}
 	*flags = mach_read_from_4(field);
@@ -1313,32 +1312,16 @@ dict_sys_tables_rec_read(
 
 	*flags = dict_sys_tables_type_to_tf(type, *n_cols);
 
-	/* For tables created with old versions of InnoDB, there may be
-	garbage in SYS_TABLES.MIX_LEN where flags2 are found. Such tables
-	would always be in ROW_FORMAT=REDUNDANT which do not have the
-	high bit set in n_cols, and flags would be zero. */
-	if (*flags != 0 || *n_cols & DICT_N_COLS_COMPACT) {
-
-		/* Get flags2 from SYS_TABLES.MIX_LEN */
-		field = rec_get_nth_field_old(
-			rec, DICT_FLD__SYS_TABLES__MIX_LEN, &len);
-		*flags2 = mach_read_from_4(field);
-
-		if (!dict_tf2_is_valid(*flags, *flags2)) {
-			ib::error() << "Table " << table_name << " in InnoDB"
-				" data dictionary contains invalid flags."
-				" SYS_TABLES.MIX_LEN=" << *flags2;
-			*flags2 = ULINT_UNDEFINED;
-			return(false);
-		}
-
-		/* DICT_TF2_FTS will be set when indexes are being loaded */
-		*flags2 &= ~DICT_TF2_FTS;
+	/* Get flags2 from SYS_TABLES.MIX_LEN */
+	field = rec_get_nth_field_old(
+		rec, DICT_FLD__SYS_TABLES__MIX_LEN, &len);
+	*flags2 = mach_read_from_4(field);
 
-		/* Now that we have used this bit, unset it. */
-		*n_cols &= ~DICT_N_COLS_COMPACT;
-	}
+	/* DICT_TF2_FTS will be set when indexes are being loaded */
+	*flags2 &= ~DICT_TF2_FTS;
 
+	/* Now that we have used this bit, unset it. */
+	*n_cols &= ~DICT_N_COLS_COMPACT;
 	return(true);
 }
 
@@ -1431,10 +1414,10 @@ dict_check_sys_tables(
 		and the tablespace_name are the same.
 		Some hidden tables like FTS AUX tables may not be found in
 		the dictionary since they can always be found in the default
-		location. If so, then dict_get_space_name() will return NULL,
+		location. If so, then dict_space_get_name() will return NULL,
 		the space name must be the table_name, and the filepath can be
 		discovered in the default location.*/
-		char*	shared_space_name = dict_get_space_name(space_id, NULL);
+		char*	shared_space_name = dict_space_get_name(space_id, NULL);
 		space_name = shared_space_name == NULL
 			? table_name.m_name
 			: shared_space_name;
@@ -1468,17 +1451,13 @@ dict_check_sys_tables(
 		opened. */
 		char*	filepath = dict_get_first_path(space_id);
 
-			/* We need to read page 0 to get (optional) IV
-			regardless if encryptions is turned on or not,
-			since if it's off we should decrypt a potentially
-			already encrypted table */
-			bool read_page_0 = true;
-
 		/* Check that the .ibd file exists. */
 		bool	is_temp = flags2 & DICT_TF2_TEMPORARY;
-		ulint	fsp_flags = dict_tf_to_fsp_flags(flags, is_temp);
-
-		validate = true;
+		bool	is_encrypted = flags2 & DICT_TF2_ENCRYPTION;
+		ulint	fsp_flags = dict_tf_to_fsp_flags(flags,
+							 is_temp,
+							 is_encrypted);
+		validate = true; /* Encryption */
 
 		dberr_t	err = fil_ibd_open(
 			validate,
@@ -2601,7 +2580,7 @@ dict_load_indexes(
 				dictionary cache for such metadata corruption,
 				since we would always be able to set it
 				when loading the dictionary cache */
-				ut_ad(index->table == table);
+				index->table = table;
 				dict_set_corrupted_index_cache_only(index);
 
 				ib::info() << "Index is corrupt but forcing"
@@ -2848,7 +2827,7 @@ dict_get_and_save_space_name(
 			dict_mutex_enter_for_mysql();
 		}
 
-		table->tablespace = dict_get_space_name(
+		table->tablespace = dict_space_get_name(
 			table->space, table->heap);
 
 		if (!dict_mutex_own) {
@@ -2948,7 +2927,7 @@ dict_load_tablespace(
 	if (DICT_TF_HAS_SHARED_SPACE(table->flags)) {
 		if (srv_sys_tablespaces_open) {
 			shared_space_name =
-				dict_get_space_name(table->space, NULL);
+				dict_space_get_name(table->space, NULL);
 
 		} else {
 			/* Make the temporary tablespace name. */
@@ -3012,7 +2991,9 @@ dict_load_tablespace(
 
 	/* Try to open the tablespace.  We set the 2nd param (fix_dict) to
 	false because we do not have an x-lock on dict_operation_lock */
-	ulint fsp_flags = dict_tf_to_fsp_flags(table->flags, false);
+	ulint fsp_flags = dict_tf_to_fsp_flags(table->flags,
+					       false,
+					       dict_table_is_encrypted(table));
 	dberr_t err = fil_ibd_open(
 		true, false, FIL_TYPE_TABLESPACE, table->space,
 		fsp_flags, space_name, filepath, table);
@@ -3179,6 +3160,32 @@ dict_load_table_one(
 		}
 	}
 
+	/* We don't trust the table->flags2(retrieved from SYS_TABLES.MIX_LEN
+	field) if the datafiles are from 3.23.52 version. To identify this
+	version, we do the below check and reset the flags. */
+	if (!DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
+	    && table->space == srv_sys_space.space_id()
+	    && table->flags == 0) {
+		table->flags2 = 0;
+	}
+
+	DBUG_EXECUTE_IF("ib_table_invalid_flags",
+			if(strcmp(table->name.m_name, "test/t1") == 0) {
+				table->flags2 = 255;
+				table->flags = 255;
+			});
+
+	if (!dict_tf2_is_valid(table->flags, table->flags2)) {
+		ib::error() << "Table " << table->name << " in InnoDB"
+			" data dictionary contains invalid flags."
+			" SYS_TABLES.MIX_LEN=" << table->flags2;
+		table->flags2 &= ~(DICT_TF2_TEMPORARY|DICT_TF2_INTRINSIC);
+		dict_table_remove_from_cache(table);
+		table = NULL;
+		err = DB_FAIL;
+		goto func_exit;
+	}
+
 	/* Initialize table foreign_child value. Its value could be
 	changed when dict_load_foreigns() is called below */
 	table->fk_max_recusive_level = 0;
@@ -3203,6 +3210,7 @@ dict_load_table_one(
 			dict_table_remove_from_cache(table);
 			table = NULL;
 		} else {
+			dict_mem_table_fill_foreign_vcol_set(table);
 			table->fk_max_recusive_level = 0;
 		}
 	} else {
@@ -3353,99 +3361,6 @@ dict_load_table_on_id(
 	return(table);
 }
 
-/***********************************************************************//**
-Loads a table id based on the index id.
- at return	true if found */
-static
-bool
-dict_load_table_id_on_index_id(
-/*==================*/
-	index_id_t		index_id,  /*!< in: index id */
-	table_id_t*		table_id) /*!< out: table id */
-{
-	/* check hard coded indexes */
-	switch(index_id) {
-	case DICT_TABLES_ID:
-	case DICT_COLUMNS_ID:
-	case DICT_INDEXES_ID:
-	case DICT_FIELDS_ID:
-		*table_id = index_id;
-		return true;
-	case DICT_TABLE_IDS_ID:
-		/* The following is a secondary index on SYS_TABLES */
-		*table_id = DICT_TABLES_ID;
-		return true;
-	}
-
-	bool		found = false;
-	mtr_t		mtr;
-
-	ut_ad(mutex_own(&(dict_sys->mutex)));
-
-	/* NOTE that the operation of this function is protected by
-	the dictionary mutex, and therefore no deadlocks can occur
-	with other dictionary operations. */
-
-	mtr_start(&mtr);
-
-	btr_pcur_t pcur;
-	const rec_t* rec = dict_startscan_system(&pcur, &mtr, SYS_INDEXES);
-
-	while (rec) {
-		ulint len;
-		const byte* field = rec_get_nth_field_old(
-			rec, DICT_FLD__SYS_INDEXES__ID, &len);
-		ut_ad(len == 8);
-
-		/* Check if the index id is the one searched for */
-		if (index_id == mach_read_from_8(field)) {
-			found = true;
-			/* Now we get the table id */
-			const byte* field = rec_get_nth_field_old(
-				rec,
-				DICT_FLD__SYS_INDEXES__TABLE_ID,
-				&len);
-			*table_id = mach_read_from_8(field);
-			break;
-		}
-		mtr_commit(&mtr);
-		mtr_start(&mtr);
-		rec = dict_getnext_system(&pcur, &mtr);
-	}
-
-	btr_pcur_close(&pcur);
-	mtr_commit(&mtr);
-
-	return(found);
-}
-
-UNIV_INTERN
-dict_table_t*
-dict_table_open_on_index_id(
-/*==================*/
-	index_id_t index_id,	/*!< in: index id */
-	bool dict_locked)	/*!< in: dict locked */
-{
-	if (!dict_locked) {
-		mutex_enter(&dict_sys->mutex);
-	}
-
-	ut_ad(mutex_own(&dict_sys->mutex));
-	table_id_t table_id;
-	dict_table_t * table = NULL;
-	if (dict_load_table_id_on_index_id(index_id, &table_id)) {
-		bool local_dict_locked = true;
-		table = dict_table_open_on_id(table_id,
-					      local_dict_locked,
-					      DICT_TABLE_OP_LOAD_TABLESPACE);
-	}
-
-	if (!dict_locked) {
-		mutex_exit(&dict_sys->mutex);
-	}
-	return table;
-}
-
 /********************************************************************//**
 This function is called when the database is booted. Loads system table
 index definitions except for the clustered index which is added to the
@@ -3953,3 +3868,96 @@ dict_load_foreigns(
 
 	DBUG_RETURN(DB_SUCCESS);
 }
+
+/***********************************************************************//**
+Loads a table id based on the index id.
+ at return	true if found */
+static
+bool
+dict_load_table_id_on_index_id(
+/*===========================*/
+	index_id_t		index_id,  /*!< in: index id */
+	table_id_t*		table_id) /*!< out: table id */
+{
+	/* check hard coded indexes */
+	switch(index_id) {
+	case DICT_TABLES_ID:
+	case DICT_COLUMNS_ID:
+	case DICT_INDEXES_ID:
+	case DICT_FIELDS_ID:
+		*table_id = index_id;
+		return true;
+	case DICT_TABLE_IDS_ID:
+		/* The following is a secondary index on SYS_TABLES */
+		*table_id = DICT_TABLES_ID;
+		return true;
+	}
+
+	bool		found = false;
+	mtr_t		mtr;
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	/* NOTE that the operation of this function is protected by
+	the dictionary mutex, and therefore no deadlocks can occur
+	with other dictionary operations. */
+
+	mtr_start(&mtr);
+
+	btr_pcur_t pcur;
+	const rec_t* rec = dict_startscan_system(&pcur, &mtr, SYS_INDEXES);
+
+	while (rec) {
+		ulint len;
+		const byte* field = rec_get_nth_field_old(
+			rec, DICT_FLD__SYS_INDEXES__ID, &len);
+		ut_ad(len == 8);
+
+		/* Check if the index id is the one searched for */
+		if (index_id == mach_read_from_8(field)) {
+			found = true;
+			/* Now we get the table id */
+			const byte* field = rec_get_nth_field_old(
+				rec,
+				DICT_FLD__SYS_INDEXES__TABLE_ID,
+				&len);
+			*table_id = mach_read_from_8(field);
+			break;
+		}
+		mtr_commit(&mtr);
+		mtr_start(&mtr);
+		rec = dict_getnext_system(&pcur, &mtr);
+	}
+
+	btr_pcur_close(&pcur);
+	mtr_commit(&mtr);
+
+	return(found);
+}
+
+UNIV_INTERN
+dict_table_t*
+dict_table_open_on_index_id(
+/*========================*/
+	index_id_t index_id,	/*!< in: index id */
+	bool dict_locked)	/*!< in: dict locked */
+{
+	if (!dict_locked) {
+		mutex_enter(&dict_sys->mutex);
+	}
+
+	ut_ad(mutex_own(&dict_sys->mutex));
+	table_id_t table_id;
+	dict_table_t * table = NULL;
+	if (dict_load_table_id_on_index_id(index_id, &table_id)) {
+		bool local_dict_locked = true;
+		table = dict_table_open_on_id(table_id,
+					      local_dict_locked,
+					      DICT_TABLE_OP_LOAD_TABLESPACE);
+	}
+
+	if (!dict_locked) {
+		mutex_exit(&dict_sys->mutex);
+	}
+	return table;
+}
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index 89e9861..b0d679d 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -190,36 +190,6 @@ dict_mem_table_create(
 }
 
 /****************************************************************//**
-Determines if a table belongs to a system database
- at return */
-UNIV_INTERN
-bool
-dict_mem_table_is_system(
-/*================*/
-	char	*name)		/*!< in: table name */
-{
-	ut_ad(name);
-
-	/* table has the following format: database/table
-	and some system table are of the form SYS_* */
-	if (strchr(name, '/')) {
-		int table_len = strlen(name);
-		const char *system_db;
-		int i = 0;
-		while ((system_db = innobase_system_databases[i++])
-			&& (system_db != NullS)) {
-			int len = strlen(system_db);
-			if (table_len > len && !strncmp(name, system_db, len)) {
-				return true;
-			}
-		}
-		return false;
-	} else {
-		return true;
-	}
-}
-
-/****************************************************************//**
 Free a table memory object. */
 void
 dict_mem_table_free(
@@ -243,6 +213,7 @@ dict_mem_table_free(
 	dict_table_autoinc_destroy(table);
 #endif /* UNIV_HOTBACKUP */
 
+	dict_mem_table_free_foreign_vcol_set(table);
 	dict_table_stats_latch_destroy(table);
 
 	table->foreign_set.~dict_foreign_set();
@@ -260,6 +231,10 @@ dict_mem_table_free(
 		UT_DELETE(vcol->v_indexes);
 	}
 
+	if (table->s_cols != NULL) {
+		UT_DELETE(table->s_cols);
+	}
+
 	mem_heap_free(table->heap);
 }
 
@@ -433,6 +408,39 @@ dict_mem_table_add_v_col(
 	return(v_col);
 }
 
+/** Adds a stored column definition to a table.
+ at param[in]	table		table
+ at param[in]	num_base	number of base columns. */
+void
+dict_mem_table_add_s_col(
+	dict_table_t*	table,
+	ulint		num_base)
+{
+	ulint	i = table->n_def - 1;
+	dict_col_t*	col = dict_table_get_nth_col(table, i);
+	dict_s_col_t	s_col;
+
+	ut_ad(col != NULL);
+
+	if (table->s_cols == NULL) {
+		table->s_cols = UT_NEW_NOKEY(dict_s_col_list());
+	}
+
+	s_col.m_col = col;
+	s_col.s_pos = i + table->n_v_def;
+
+	if (num_base != 0) {
+		s_col.base_col = static_cast<dict_col_t**>(mem_heap_zalloc(
+			table->heap, num_base * sizeof(dict_col_t*)));
+	} else {
+		s_col.base_col = NULL;
+	}
+
+	s_col.num_base = num_base;
+	table->s_cols->push_back(s_col);
+}
+
+
 /**********************************************************************//**
 Renames a column of a table in the data dictionary cache. */
 static MY_ATTRIBUTE((nonnull))
@@ -452,7 +460,9 @@ dict_mem_table_col_rename_low(
 
 	size_t from_len = strlen(s), to_len = strlen(to);
 
-	ut_ad(i < table->n_def);
+	ut_ad(i < table->n_def || is_virtual);
+	ut_ad(i < table->n_v_def || !is_virtual);
+
 	ut_ad(from_len <= NAME_LEN);
 	ut_ad(to_len <= NAME_LEN);
 
@@ -592,7 +602,7 @@ void
 dict_mem_table_col_rename(
 /*======================*/
 	dict_table_t*	table,	/*!< in/out: table */
-	unsigned	nth_col,/*!< in: column index */
+	ulint		nth_col,/*!< in: column index */
 	const char*	from,	/*!< in: old column name */
 	const char*	to,	/*!< in: new column name */
 	bool		is_virtual)
@@ -603,7 +613,7 @@ dict_mem_table_col_rename(
 	ut_ad((!is_virtual && nth_col < table->n_def)
 	       || (is_virtual && nth_col < table->n_v_def));
 
-	for (unsigned i = 0; i < nth_col; i++) {
+	for (ulint i = 0; i < nth_col; i++) {
 		size_t	len = strlen(s);
 		ut_ad(len > 0);
 		s += len + 1;
@@ -613,7 +623,8 @@ dict_mem_table_col_rename(
 	Proceed with the renaming anyway. */
 	ut_ad(!strcmp(from, s));
 
-	dict_mem_table_col_rename_low(table, nth_col, to, s, is_virtual);
+	dict_mem_table_col_rename_low(table, static_cast<unsigned>(nth_col),
+				      to, s, is_virtual);
 }
 
 /**********************************************************************//**
@@ -709,6 +720,8 @@ dict_mem_foreign_create(void)
 
 	foreign->heap = heap;
 
+	foreign->v_cols = NULL;
+
 	DBUG_PRINT("dict_mem_foreign_create", ("heap: %p", heap));
 
 	DBUG_RETURN(foreign);
@@ -773,6 +786,181 @@ dict_mem_referenced_table_name_lookup_set(
 			= foreign->referenced_table_name;
 	}
 }
+
+/** Fill the virtual column set with virtual column information
+present in the given virtual index.
+ at param[in]	index	virtual index
+ at param[out]	v_cols	virtual column set. */
+static
+void
+dict_mem_fill_vcol_has_index(
+	const dict_index_t*	index,
+	dict_vcol_set**		v_cols)
+{
+	for (ulint i = 0; i < index->table->n_v_cols; i++) {
+		dict_v_col_t*	v_col = dict_table_get_nth_v_col(
+					index->table, i);
+		if (!v_col->m_col.ord_part) {
+			continue;
+		}
+
+		dict_v_idx_list::iterator it;
+		for (it = v_col->v_indexes->begin();
+		     it != v_col->v_indexes->end(); ++it) {
+			dict_v_idx_t	v_idx = *it;
+
+			if (v_idx.index != index) {
+				continue;
+			}
+
+			if (*v_cols == NULL) {
+				*v_cols = UT_NEW_NOKEY(dict_vcol_set());
+			}
+
+			(*v_cols)->insert(v_col);
+		}
+	}
+}
+
+/** Fill the virtual column set with the virtual column of the index
+if the index contains given column name.
+ at param[in]	col_name	column name
+ at param[in]	table		innodb table object
+ at param[out]	v_cols		set of virtual column information. */
+static
+void
+dict_mem_fill_vcol_from_v_indexes(
+	const char*		col_name,
+	const dict_table_t*	table,
+	dict_vcol_set**		v_cols)
+{
+	/* virtual column can't be Primary Key, so start with
+	secondary index */
+	for (dict_index_t* index = dict_table_get_next_index(
+			dict_table_get_first_index(table));
+		index;
+		index = dict_table_get_next_index(index)) {
+
+		if (!dict_index_has_virtual(index)) {
+			continue;
+		}
+
+		for (ulint i = 0; i < index->n_fields; i++) {
+			dict_field_t*	field =
+				dict_index_get_nth_field(index, i);
+
+			if (strcmp(field->name, col_name) == 0) {
+				dict_mem_fill_vcol_has_index(
+					index, v_cols);
+			}
+		}
+	}
+}
+
+/** Fill the virtual column set with virtual columns which have base columns
+as the given col_name
+ at param[in]	col_name	column name
+ at param[in]	table		table object
+ at param[out]	v_cols		set of virtual columns. */
+static
+void
+dict_mem_fill_vcol_set_for_base_col(
+	const char*		col_name,
+	const dict_table_t*	table,
+	dict_vcol_set**		v_cols)
+{
+	for (ulint i = 0; i < table->n_v_cols; i++) {
+		dict_v_col_t*	v_col = dict_table_get_nth_v_col(table, i);
+
+		if (!v_col->m_col.ord_part) {
+			continue;
+		}
+
+		for (ulint j = 0; j < v_col->num_base; j++) {
+			if (strcmp(col_name, dict_table_get_col_name(
+					table,
+					v_col->base_col[j]->ind)) == 0) {
+
+				if (*v_cols == NULL) {
+					*v_cols = UT_NEW_NOKEY(dict_vcol_set());
+				}
+
+				(*v_cols)->insert(v_col);
+			}
+		}
+	}
+}
+
+/** Fills the dependent virtual columns in a set.
+Reason for being dependent are
+1) FK can be present on base column of virtual columns
+2) FK can be present on column which is a part of virtual index
+ at param[in,out]  foreign foreign key information. */
+void
+dict_mem_foreign_fill_vcol_set(
+        dict_foreign_t* foreign)
+{
+	ulint	type = foreign->type;
+
+	if (type == 0) {
+		return;
+	}
+
+	for (ulint i = 0; i < foreign->n_fields; i++) {
+		/** FK can be present on base columns
+		of virtual columns. */
+		dict_mem_fill_vcol_set_for_base_col(
+			foreign->foreign_col_names[i],
+			foreign->foreign_table,
+			&foreign->v_cols);
+
+		/** FK can be present on the columns
+		which can be a part of virtual index. */
+		dict_mem_fill_vcol_from_v_indexes(
+			foreign->foreign_col_names[i],
+			foreign->foreign_table,
+			&foreign->v_cols);
+	}
+}
+
+/** Fill virtual columns set in each fk constraint present in the table.
+ at param[in,out]	table	innodb table object. */
+void
+dict_mem_table_fill_foreign_vcol_set(
+	dict_table_t*	table)
+{
+	dict_foreign_set	fk_set = table->foreign_set;
+	dict_foreign_t*		foreign;
+
+	dict_foreign_set::iterator it;
+	for (it = fk_set.begin(); it != fk_set.end(); ++it) {
+		foreign = *it;
+
+		dict_mem_foreign_fill_vcol_set(foreign);
+	}
+}
+
+/** Free the vcol_set from all foreign key constraint on the table.
+ at param[in,out]	table	innodb table object. */
+void
+dict_mem_table_free_foreign_vcol_set(
+	dict_table_t*	table)
+{
+	dict_foreign_set	fk_set = table->foreign_set;
+	dict_foreign_t*		foreign;
+
+	dict_foreign_set::iterator it;
+	for (it = fk_set.begin(); it != fk_set.end(); ++it) {
+
+		foreign = *it;
+
+		if (foreign->v_cols != NULL) {
+			UT_DELETE(foreign->v_cols);
+			foreign->v_cols = NULL;
+		}
+	}
+}
+
 #endif /* !UNIV_HOTBACKUP */
 
 /**********************************************************************//**
@@ -942,3 +1130,32 @@ operator<< (std::ostream& out, const dict_foreign_set& fk_set)
 	return(out);
 }
 
+/****************************************************************//**
+Determines if a table belongs to a system database
+ at return */
+bool
+dict_mem_table_is_system(
+/*================*/
+	char	*name)		/*!< in: table name */
+{
+	ut_ad(name);
+
+	/* table has the following format: database/table
+	and some system table are of the form SYS_* */
+	if (strchr(name, '/')) {
+		int table_len = strlen(name);
+		const char *system_db;
+		int i = 0;
+		while ((system_db = innobase_system_databases[i++])
+			&& (system_db != NullS)) {
+			int len = strlen(system_db);
+			if (table_len > len && !strncmp(name, system_db, len)) {
+				return true;
+			}
+		}
+		return false;
+	} else {
+		return true;
+	}
+}
+
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index 67bf672..3c25e37 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -930,14 +930,14 @@ dict_stats_update_transient(
 
 	if (dict_table_is_discarded(table)) {
 		/* Nothing to do. */
-		dict_stats_empty_table(table, false);
+		dict_stats_empty_table(table, true);
 		return;
 	} else if (index == NULL) {
 		/* Table definition is corrupt */
 
 		ib::warn() << "Table " << table->name
 			<< " has no indexes. Cannot calculate statistics.";
-		dict_stats_empty_table(table, false);
+		dict_stats_empty_table(table, true);
 		return;
 	}
 
@@ -2316,7 +2316,6 @@ storage.
 allocate and free the trx object. If it is not NULL then it will be
 rolled back only in the case of error, but not freed.
 @return DB_SUCCESS or error code */
-static
 dberr_t
 dict_stats_save_index_stat(
 	dict_index_t*	index,
@@ -3257,15 +3256,15 @@ dict_stats_update(
 
 			if (innodb_table_stats_not_found == false &&
 			    table->stats_error_printed == false) {
-			ib::error() << "Fetch of persistent statistics"
-				" requested for table "
-				<< table->name
-				<< " but the required system tables "
-				<< TABLE_STATS_NAME_PRINT
-				<< " and " << INDEX_STATS_NAME_PRINT
-				<< " are not present or have unexpected"
-				" structure. Using transient stats instead.";
-				table->stats_error_printed = true;
+				ib::error() << "Fetch of persistent statistics"
+					" requested for table "
+					<< table->name
+					<< " but the required system tables "
+					<< TABLE_STATS_NAME_PRINT
+					<< " and " << INDEX_STATS_NAME_PRINT
+					<< " are not present or have unexpected"
+					" structure. Using transient stats instead.";
+					table->stats_error_printed = true;
 			}
 
 			goto transient;
@@ -3337,12 +3336,12 @@ dict_stats_update(
 
 			if (innodb_table_stats_not_found == false &&
 			    table->stats_error_printed == false) {
-			ib::error() << "Error fetching persistent statistics"
-				" for table "
-				<< table->name
-				<< " from " TABLE_STATS_NAME_PRINT " and "
-				INDEX_STATS_NAME_PRINT ": " << ut_strerr(err)
-				<< ". Using transient stats method instead.";
+				ib::error() << "Error fetching persistent statistics"
+					" for table "
+					<< table->name
+					<< " from " TABLE_STATS_NAME_PRINT " and "
+					INDEX_STATS_NAME_PRINT ": " << ut_strerr(err)
+					<< ". Using transient stats method instead.";
 			}
 
 			goto transient;
@@ -3842,120 +3841,6 @@ dict_stats_rename_table(
 }
 
 /*********************************************************************//**
-Save defragmentation result.
- at return DB_SUCCESS or error code */
-UNIV_INTERN
-dberr_t
-dict_stats_save_defrag_summary(
-	dict_index_t*	index)	/*!< in: index */
-{
-	dberr_t	ret;
-	lint	now = (lint) ut_time();
-
-	if (dict_stats_should_ignore_index(index)) {
-		return DB_SUCCESS;
-	}
-
-	rw_lock_x_lock(dict_operation_lock);
-	mutex_enter(&dict_sys->mutex);
-	ret = dict_stats_save_index_stat(index, now, "n_pages_freed",
-					 index->stat_defrag_n_pages_freed,
-					 NULL,
-					 "Number of pages freed during"
-					 " last defragmentation run.",
-					 NULL);
-
-	mutex_exit(&dict_sys->mutex);
-	rw_lock_x_unlock(dict_operation_lock);
-	return (ret);
-}
-
-/*********************************************************************//**
-Save defragmentation stats for a given index.
- at return DB_SUCCESS or error code */
-UNIV_INTERN
-dberr_t
-dict_stats_save_defrag_stats(
-	dict_index_t*	index)	/*!< in: index */
-{
-	dberr_t	ret;
-
-	if (index->table->ibd_file_missing) {
-		ut_print_timestamp(stderr);
-		fprintf(stderr,
-			" InnoDB: Cannot save defragment stats because "
-			".ibd file is missing.\n");
-		return (DB_TABLESPACE_DELETED);
-	}
-	if (dict_index_is_corrupted(index)) {
-		ut_print_timestamp(stderr);
-		fprintf(stderr,
-			" InnoDB: Cannot save defragment stats because "
-			"index is corrupted.\n");
-		return(DB_CORRUPTION);
-	}
-
-	if (dict_stats_should_ignore_index(index)) {
-		return DB_SUCCESS;
-	}
-
-	lint	now = (lint) ut_time();
-	mtr_t	mtr;
-	ulint	n_leaf_pages=0;
-	ulint	n_leaf_reserved=0;
-	mtr_start(&mtr);
-	mtr_s_lock(dict_index_get_lock(index), &mtr);
-
-	n_leaf_reserved = btr_get_size_and_reserved(index, BTR_N_LEAF_PAGES,
-						    &n_leaf_pages, &mtr);
-	mtr_commit(&mtr);
-
-	if (n_leaf_reserved == ULINT_UNDEFINED) {
-		// The index name is different during fast index creation,
-		// so the stats won't be associated with the right index
-		// for later use. We just return without saving.
-		return DB_SUCCESS;
-	}
-
-	rw_lock_x_lock(dict_operation_lock);
-
-	mutex_enter(&dict_sys->mutex);
-	ret = dict_stats_save_index_stat(index, now, "n_page_split",
-					 index->stat_defrag_n_page_split,
-					 NULL,
-					 "Number of new page splits on leaves"
-					 " since last defragmentation.",
-					 NULL);
-	if (ret != DB_SUCCESS) {
-		goto end;
-	}
-
-	ret = dict_stats_save_index_stat(
-		index, now, "n_leaf_pages_defrag",
-		n_leaf_pages,
-		NULL,
-		"Number of leaf pages when this stat is saved to disk",
-		NULL);
-	if (ret != DB_SUCCESS) {
-		goto end;
-	}
-
-	ret = dict_stats_save_index_stat(
-		index, now, "n_leaf_pages_reserved",
-		n_leaf_reserved,
-		NULL,
-		"Number of pages reserved for this index leaves when this stat "
-		"is saved to disk",
-		NULL);
-
-end:
-	mutex_exit(&dict_sys->mutex);
-	rw_lock_x_unlock(dict_operation_lock);
-
-	return (ret);
-}
-
-/*********************************************************************//**
 Renames an index in InnoDB persistent stats storage.
 This function creates its own transaction and commits it.
 @return DB_SUCCESS or error code. DB_STATS_DO_NOT_EXIST will be returned
diff --git a/storage/innobase/dict/dict0stats_bg.cc b/storage/innobase/dict/dict0stats_bg.cc
index eca3756..dbc8e90 100644
--- a/storage/innobase/dict/dict0stats_bg.cc
+++ b/storage/innobase/dict/dict0stats_bg.cc
@@ -24,9 +24,9 @@ Created Apr 25, 2012 Vasil Dimov
 *******************************************************/
 
 #include "dict0dict.h"
-#include "dict0dict.h"
 #include "dict0stats.h"
 #include "dict0stats_bg.h"
+#include "dict0defrag_bg.h"
 #include "row0mysql.h"
 #include "srv0start.h"
 #include "ut0new.h"
@@ -45,15 +45,27 @@ Created Apr 25, 2012 Vasil Dimov
 /** Event to wake up the stats thread */
 os_event_t			dict_stats_event = NULL;
 
+/** Variable to initiate shutdown the dict stats thread. Note we don't
+use 'srv_shutdown_state' because we want to shutdown dict stats thread
+before purge thread. */
+bool				dict_stats_start_shutdown = false;
+
+/** Event to wait for shutdown of the dict stats thread */
+os_event_t			dict_stats_shutdown_event = NULL;
+
+#ifdef UNIV_DEBUG
+/** Used by SET GLOBAL innodb_dict_stats_disabled_debug = 1; */
+my_bool				innodb_dict_stats_disabled_debug;
+
+static os_event_t		dict_stats_disabled_event;
+#endif /* UNIV_DEBUG */
+
 /** This mutex protects the "recalc_pool" variable. */
 static ib_mutex_t		recalc_pool_mutex;
-static ib_mutex_t		defrag_pool_mutex;
-static mysql_pfs_key_t		defrag_pool_mutex_key;
 
 /** The number of tables that can be added to "recalc_pool" before
 it is enlarged */
 static const ulint		RECALC_POOL_INITIAL_SLOTS = 128;
-static const ulint		DEFRAG_POOL_INITIAL_SLOTS = 128;
 
 /** Allocator type, used by std::vector */
 typedef ut_allocator<table_id_t>
@@ -73,39 +85,23 @@ typedef recalc_pool_t::iterator
 by background statistics gathering. */
 static recalc_pool_t*		recalc_pool;
 
-/** Indices whose defrag stats need to be saved to persistent storage.*/
-struct defrag_pool_item_t {
-	table_id_t	table_id;
-	index_id_t	index_id;
-};
-
-typedef ut_allocator<defrag_pool_item_t>
-	defrag_pool_allocator_t;
-typedef std::vector<defrag_pool_item_t, defrag_pool_allocator_t>
-	defrag_pool_t;
-static defrag_pool_t*			defrag_pool;
-typedef defrag_pool_t::iterator		defrag_pool_iterator_t;
 
 /*****************************************************************//**
 Initialize the recalc pool, called once during thread initialization. */
 static
 void
-dict_stats_pool_init()
+dict_stats_recalc_pool_init()
 /*=========================*/
 {
 	ut_ad(!srv_read_only_mode);
 	/* JAN: TODO: MySQL 5.7 PSI
 	const PSI_memory_key	key = mem_key_dict_stats_bg_recalc_pool_t;
-	const PSI_memory_key	key2 = mem_key_dict_defrag_pool_t;
 
 	recalc_pool = UT_NEW(recalc_pool_t(recalc_pool_allocator_t(key)), key);
-	defrag_pool = UT_NEW(defrag_pool_t(defrag_pool_allocator_t(key2)), key2);
 
-	defrag_pool->reserve(DEFRAG_POOL_INITIAL_SLOTS);
 	recalc_pool->reserve(RECALC_POOL_INITIAL_SLOTS);
 	*/
 	recalc_pool = new std::vector<table_id_t, recalc_pool_allocator_t>();
-	defrag_pool = new std::vector<defrag_pool_item_t, defrag_pool_allocator_t>();
 }
 
 /*****************************************************************//**
@@ -113,16 +109,14 @@ Free the resources occupied by the recalc pool, called once during
 thread de-initialization. */
 static
 void
-dict_stats_pool_deinit()
-/*====================*/
+dict_stats_recalc_pool_deinit()
+/*===========================*/
 {
 	ut_ad(!srv_read_only_mode);
 
 	recalc_pool->clear();
-	defrag_pool->clear();
 
 	UT_DELETE(recalc_pool);
-	UT_DELETE(defrag_pool);
 }
 
 /*****************************************************************//**
@@ -217,111 +211,6 @@ dict_stats_recalc_pool_del(
 }
 
 /*****************************************************************//**
-Add an index in a table to the defrag pool, which is processed by the
-background stats gathering thread. Only the table id and index id are
-added to the list, so the table can be closed after being enqueued and
-it will be opened when needed. If the table or index does not exist later
-(has been DROPped), then it will be removed from the pool and skipped. */
-UNIV_INTERN
-void
-dict_stats_defrag_pool_add(
-/*=======================*/
-	const dict_index_t*	index)	/*!< in: table to add */
-{
-	defrag_pool_item_t item;
-
-	ut_ad(!srv_read_only_mode);
-
-	mutex_enter(&defrag_pool_mutex);
-
-	/* quit if already in the list */
-	for (defrag_pool_iterator_t iter = defrag_pool->begin();
-	     iter != defrag_pool->end();
-	     ++iter) {
-		if ((*iter).table_id == index->table->id
-		    && (*iter).index_id == index->id) {
-			mutex_exit(&defrag_pool_mutex);
-			return;
-		}
-	}
-
-	item.table_id = index->table->id;
-	item.index_id = index->id;
-	defrag_pool->push_back(item);
-
-	mutex_exit(&defrag_pool_mutex);
-
-	os_event_set(dict_stats_event);
-}
-
-/*****************************************************************//**
-Get an index from the auto defrag pool. The returned index id is removed
-from the pool.
- at return true if the pool was non-empty and "id" was set, false otherwise */
-static
-bool
-dict_stats_defrag_pool_get(
-/*=======================*/
-	table_id_t*	table_id,	/*!< out: table id, or unmodified if
-					list is empty */
-	index_id_t*	index_id)	/*!< out: index id, or unmodified if
-					list is empty */
-{
-	ut_ad(!srv_read_only_mode);
-
-	mutex_enter(&defrag_pool_mutex);
-
-	if (defrag_pool->empty()) {
-		mutex_exit(&defrag_pool_mutex);
-		return(false);
-	}
-
-	defrag_pool_item_t& item = defrag_pool->back();
-	*table_id = item.table_id;
-	*index_id = item.index_id;
-
-	defrag_pool->pop_back();
-
-	mutex_exit(&defrag_pool_mutex);
-
-	return(true);
-}
-
-/*****************************************************************//**
-Delete a given index from the auto defrag pool. */
-UNIV_INTERN
-void
-dict_stats_defrag_pool_del(
-/*=======================*/
-	const dict_table_t*	table,	/*!<in: if given, remove
-					all entries for the table */
-	const dict_index_t*	index)	/*!< in: if given, remove this index */
-{
-	ut_a((table && !index) || (!table && index));
-	ut_ad(!srv_read_only_mode);
-	ut_ad(mutex_own(&dict_sys->mutex));
-
-	mutex_enter(&defrag_pool_mutex);
-
-	defrag_pool_iterator_t iter = defrag_pool->begin();
-	while (iter != defrag_pool->end()) {
-		if ((table && (*iter).table_id == table->id)
-		    || (index
-			&& (*iter).table_id == index->table->id
-			&& (*iter).index_id == index->id)) {
-			/* erase() invalidates the iterator */
-			iter = defrag_pool->erase(iter);
-			if (index)
-				break;
-		} else {
-			iter++;
-		}
-	}
-
-	mutex_exit(&defrag_pool_mutex);
-}
-
-/*****************************************************************//**
 Wait until background stats thread has stopped using the specified table.
 The caller must have locked the data dictionary using
 row_mysql_lock_data_dictionary() and this function may unlock it temporarily
@@ -352,6 +241,9 @@ dict_stats_thread_init()
 	ut_a(!srv_read_only_mode);
 
 	dict_stats_event = os_event_create(0);
+	dict_stats_shutdown_event = os_event_create(0);
+
+	ut_d(dict_stats_disabled_event = os_event_create(0));
 
 	/* The recalc_pool_mutex is acquired from:
 	1) the background stats gathering thread before any other latch
@@ -369,10 +261,9 @@ dict_stats_thread_init()
 
 	mutex_create(LATCH_ID_RECALC_POOL, &recalc_pool_mutex);
 
-	/* We choose SYNC_STATS_DEFRAG to be below SYNC_FSP_PAGE. */
-	mutex_create(LATCH_ID_DEFRAGMENT_MUTEX, &defrag_pool_mutex);
+	dict_stats_recalc_pool_init();
+	dict_defrag_pool_init();
 
-	dict_stats_pool_init();
 }
 
 /*****************************************************************//**
@@ -385,13 +276,21 @@ dict_stats_thread_deinit()
 	ut_a(!srv_read_only_mode);
 	ut_ad(!srv_dict_stats_thread_active);
 
-	dict_stats_pool_deinit();
+	dict_stats_recalc_pool_deinit();
+	dict_defrag_pool_deinit();
 
 	mutex_free(&recalc_pool_mutex);
-	mutex_free(&defrag_pool_mutex);
+
+#ifdef UNIV_DEBUG
+	os_event_destroy(dict_stats_disabled_event);
+	dict_stats_disabled_event = NULL;
+#endif /* UNIV_DEBUG */
 
 	os_event_destroy(dict_stats_event);
+	os_event_destroy(dict_stats_shutdown_event);
 	dict_stats_event = NULL;
+	dict_stats_shutdown_event = NULL;
+	dict_stats_start_shutdown = false;
 }
 
 /*****************************************************************//**
@@ -459,69 +358,43 @@ dict_stats_process_entry_from_recalc_pool()
 
 	mutex_enter(&dict_sys->mutex);
 
-	table->stats_bg_flag &= ~BG_STAT_IN_PROGRESS;
+	table->stats_bg_flag = BG_STAT_NONE;
 
 	dict_table_close(table, TRUE, FALSE);
 
 	mutex_exit(&dict_sys->mutex);
 }
 
-/*****************************************************************//**
-Get the first index that has been added for updating persistent defrag
-stats and eventually save its stats. */
-static
+#ifdef UNIV_DEBUG
+/** Disables dict stats thread. It's used by:
+	SET GLOBAL innodb_dict_stats_disabled_debug = 1 (0).
+ at param[in]	thd		thread handle
+ at param[in]	var		pointer to system variable
+ at param[out]	var_ptr		where the formal string goes
+ at param[in]	save		immediate result from check function */
 void
-dict_stats_process_entry_from_defrag_pool()
-/*=======================================*/
+dict_stats_disabled_debug_update(
+	THD*				thd,
+	struct st_mysql_sys_var*	var,
+	void*				var_ptr,
+	const void*			save)
 {
-	table_id_t	table_id;
-	index_id_t	index_id;
-
-	ut_ad(!srv_read_only_mode);
-
-	/* pop the first index from the auto defrag pool */
-	if (!dict_stats_defrag_pool_get(&table_id, &index_id)) {
-		/* no index in defrag pool */
-		return;
-	}
-
-	dict_table_t*	table;
-
-	mutex_enter(&dict_sys->mutex);
-
-	/* If the table is no longer cached, we've already lost the in
-	memory stats so there's nothing really to write to disk. */
-	table = dict_table_open_on_id(table_id, TRUE,
-				      DICT_TABLE_OP_OPEN_ONLY_IF_CACHED);
-
-	if (table == NULL) {
-		mutex_exit(&dict_sys->mutex);
-		return;
-	}
+	/* This method is protected by mutex, as every SET GLOBAL .. */
+	ut_ad(dict_stats_disabled_event != NULL);
 
-	/* Check whether table is corrupted */
-	if (table->corrupted) {
-		dict_table_close(table, TRUE, FALSE);
-		mutex_exit(&dict_sys->mutex);
-		return;
-	}
-	mutex_exit(&dict_sys->mutex);
+	const bool disable = *static_cast<const my_bool*>(save);
 
-	dict_index_t*	index = dict_table_find_index_on_id(table, index_id);
+	const int64_t sig_count = os_event_reset(dict_stats_disabled_event);
 
-	if (index == NULL) {
-		return;
-	}
+	innodb_dict_stats_disabled_debug = disable;
 
-	/* Check whether index is corrupted */
-	if (dict_index_is_corrupted(index)) {
-		dict_table_close(table, FALSE, FALSE);
-		return;
+	if (disable) {
+		os_event_set(dict_stats_event);
+		os_event_wait_low(dict_stats_disabled_event, sig_count);
 	}
-
-	dict_stats_save_defrag_stats(index);
-	dict_table_close(table, FALSE, FALSE);
 }
+#endif /* UNIV_DEBUG */
+
 
 /*****************************************************************//**
 This is the thread for background stats gathering. It pops tables, from
@@ -545,7 +418,7 @@ DECLARE_THREAD(dict_stats_thread)(
 
 	srv_dict_stats_thread_active = TRUE;
 
-	while (!SHUTTING_DOWN()) {
+	while (!dict_stats_start_shutdown) {
 
 		/* Wake up periodically even if not signaled. This is
 		because we may lose an event - if the below call to
@@ -555,23 +428,44 @@ DECLARE_THREAD(dict_stats_thread)(
 		os_event_wait_time(
 			dict_stats_event, MIN_RECALC_INTERVAL * 1000000);
 
-		if (SHUTTING_DOWN()) {
+#ifdef UNIV_DEBUG
+		while (innodb_dict_stats_disabled_debug) {
+			os_event_set(dict_stats_disabled_event);
+			if (dict_stats_start_shutdown) {
+				break;
+			}
+			os_event_wait_time(
+				dict_stats_event, 100000);
+		}
+#endif /* UNIV_DEBUG */
+
+		if (dict_stats_start_shutdown) {
 			break;
 		}
 
 		dict_stats_process_entry_from_recalc_pool();
-
-		while (defrag_pool->size())
-			dict_stats_process_entry_from_defrag_pool();
+		dict_defrag_process_entries_from_defrag_pool();
 
 		os_event_reset(dict_stats_event);
 	}
 
 	srv_dict_stats_thread_active = FALSE;
 
+	os_event_set(dict_stats_shutdown_event);
+	my_thread_end();
+
 	/* We count the number of threads in os_thread_exit(). A created
 	thread should always use that to exit instead of return(). */
-	os_thread_exit(NULL);
+	os_thread_exit();
 
 	OS_THREAD_DUMMY_RETURN;
 }
+
+/** Shutdown the dict stats thread. */
+void
+dict_stats_shutdown()
+{
+	dict_stats_start_shutdown = true;
+	os_event_set(dict_stats_event);
+	os_event_wait(dict_stats_shutdown_event);
+}
diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc
index fb87262..9062bf1 100644
--- a/storage/innobase/fil/fil0crypt.cc
+++ b/storage/innobase/fil/fil0crypt.cc
@@ -2353,7 +2353,7 @@ DECLARE_THREAD(fil_crypt_thread)(
 	/* We count the number of threads in os_thread_exit(). A created
 	thread should always use that to exit and not use return() to exit. */
 
-	os_thread_exit(NULL);
+	os_thread_exit();
 
 	OS_THREAD_DUMMY_RETURN;
 }
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index a28be69..3d34de6 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -29,12 +29,13 @@ Created 10/25/1995 Heikki Tuuri
 #include "fsp0pagecompress.h"
 #include "fil0crypt.h"
 
+#ifndef UNIV_HOTBACKUP
 #include "btr0btr.h"
 #include "buf0buf.h"
-#include "buf0flu.h"
 #include "dict0boot.h"
 #include "dict0dict.h"
 #include "fsp0file.h"
+#include "fsp0file.h"
 #include "fsp0fsp.h"
 #include "fsp0space.h"
 #include "fsp0sysspace.h"
@@ -50,14 +51,28 @@ Created 10/25/1995 Heikki Tuuri
 #include "srv0start.h"
 #include "trx0purge.h"
 #include "ut0new.h"
-#ifndef UNIV_HOTBACKUP
 # include "buf0lru.h"
 # include "ibuf0ibuf.h"
 # include "os0event.h"
 # include "sync0sync.h"
-#else /* !UNIV_HOTBACKUP */
-# include "srv0srv.h"
 #endif /* !UNIV_HOTBACKUP */
+#include "buf0flu.h"
+#include "srv0start.h"
+#include "trx0purge.h"
+#include "ut0new.h"
+
+/** Tries to close a file in the LRU list. The caller must hold the fil_sys
+mutex.
+ at return true if success, false if should retry later; since i/o's
+generally complete in < 100 ms, and as InnoDB writes at most 128 pages
+from the buffer pool in a batch, and then immediately flushes the
+files, there is a good chance that the next time we find a suitable
+node from the LRU list.
+ at param[in] print_info	if true, prints information why it
+                        cannot close a file */
+static
+bool
+fil_try_to_close_file_in_LRU(bool print_info);
 
 /*
 		IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE
@@ -123,10 +138,10 @@ const char general_space_name[] = "innodb_general";
 current working directory ".", but in the MySQL Embedded Server Library
 it is an absolute path. */
 const char*	fil_path_to_mysql_datadir;
-Folder  	folder_mysql_datadir;
+Folder		folder_mysql_datadir;
 
 /** Common InnoDB file extentions */
-const char* dot_ext[] = { "", ".ibd", ".isl", ".cfg" };
+const char* dot_ext[] = { "", ".ibd", ".isl", ".cfg", ".cfp" };
 
 /** The number of fsyncs done to the log */
 ulint	fil_n_log_flushes			= 0;
@@ -144,7 +159,7 @@ fil_addr_t	fil_addr_null = {FIL_NULL, 0};
 
 /** The tablespace memory cache. This variable is NULL before the module is
 initialized. */
-static fil_system_t*	fil_system	= NULL;
+fil_system_t*	fil_system	= NULL;
 
 #ifdef UNIV_HOTBACKUP
 static ulint	srv_data_read;
@@ -349,7 +364,6 @@ fil_space_get_by_name(
 	return(space);
 }
 
-#ifndef UNIV_HOTBACKUP
 /** Look up a tablespace.
 The caller should hold an InnoDB table lock or a MDL that prevents
 the tablespace from being dropped during the operation,
@@ -369,33 +383,8 @@ fil_space_get(
 	ut_ad(space == NULL || space->purpose != FIL_TYPE_LOG);
 	return(space);
 }
-/*******************************************************************//**
-Returns the version number of a tablespace, -1 if not found.
- at return version number, -1 if the tablespace does not exist in the
-memory cache */
-UNIV_INTERN
-ib_uint64_t
-fil_space_get_version(
-/*==================*/
-	ulint	id)	/*!< in: space id */
-{
-	fil_space_t*	space;
-	ib_uint64_t	version		= -1;
-
-	ut_ad(fil_system);
-
-	mutex_enter(&fil_system->mutex);
-
-	space = fil_space_get_by_id(id);
-
-	if (space) {
-		version = space->tablespace_version;
-	}
 
-	mutex_exit(&fil_system->mutex);
-
-	return(version);
-}
+#ifndef UNIV_HOTBACKUP
 /** Returns the latch of a file space.
 @param[in]	id	space id
 @param[out]	flags	tablespace flags
@@ -592,7 +581,19 @@ fil_node_create_low(
 
 	node->block_size = stat_info.block_size;
 
-	if (!(IORequest::is_punch_hole_supported() && punch_hole)
+	/* In this debugging mode, we can overcome the limitation of some
+	OSes like Windows that support Punch Hole but have a hole size
+	effectively too large.  By setting the block size to be half the
+	page size, we can bypass one of the checks that would normally
+	turn Page Compression off.  This execution mode allows compression
+	to be tested even when full punch hole support is not available. */
+	DBUG_EXECUTE_IF("ignore_punch_hole",
+		node->block_size = ut_min(stat_info.block_size,
+					  static_cast<size_t>(UNIV_PAGE_SIZE / 2));
+	);
+
+	if (!IORequest::is_punch_hole_supported()
+	    || !punch_hole
 	    || node->block_size >= srv_page_size) {
 
 		fil_no_punch_hole(node);
@@ -650,9 +651,9 @@ fil_node_open_file(
 	bool		success;
 	byte*		buf2;
 	byte*		page;
-	ulint		space_id;
 	ulint		flags;
 	ulint		min_size;
+	ulint		space_id;
 	bool		read_only_mode;
 	fil_space_t*	space = node->space;
 
@@ -675,18 +676,22 @@ fil_node_open_file(
 		file read function os_file_read() in Windows to read
 		from a file opened for async I/O! */
 
+retry:
 		node->handle = os_file_create_simple_no_error_handling(
 			innodb_data_file_key, node->name, OS_FILE_OPEN,
 			OS_FILE_READ_ONLY, read_only_mode, &success);
 
 		if (!success) {
 			/* The following call prints an error message */
-			os_file_get_last_error(true);
+			ulint err = os_file_get_last_error(true);
+			if (err == EMFILE + 100) {
+				if (fil_try_to_close_file_in_LRU(true))
+					goto retry;
+			}
 
 			ib::warn() << "Cannot open '" << node->name << "'."
 				" Have you deleted .ibd files under a"
 				" running mysqld server?";
-
 			return(false);
 		}
 
@@ -730,30 +735,13 @@ fil_node_open_file(
 
 		if (size_bytes < min_size) {
 
-			ib::error() << "The size of tablespace file "
+			ib::error() << "The size of tablespace " << space_id << " file "
 				<< node->name << " is only " << size_bytes
 				<< ", should be at least " << min_size << "!";
 
 			ut_error;
 		}
 
-		if (space_id != space->id) {
-			ib::fatal() << "Tablespace id is " << space->id
-				<< " in the data dictionary but in file "
-				<< node->name << " it is " << space_id << "!";
-		}
-
-		const page_size_t	space_page_size(space->flags);
-
-		if (!page_size.equals_to(space_page_size)) {
-			ib::fatal() << "Tablespace file " << node->name
-				<< " has page size " << page_size
-				<< " (flags=" << ib::hex(flags) << ") but the"
-				" data dictionary expects page size "
-				<< space_page_size << " (flags="
-				<< ib::hex(space->flags) << ")!";
-		}
-
 		if (space->flags != flags) {
 			ulint sflags = (space->flags & ~FSP_FLAGS_MASK_DATA_DIR);
 			ulint fflags = (flags & ~FSP_FLAGS_MASK_DATA_DIR_ORACLE);
@@ -763,11 +751,13 @@ fil_node_open_file(
 			it. */
 
 			if (sflags == fflags) {
-				fprintf(stderr,
-					"InnoDB: Warning: Table flags 0x%lx"
-					" in the data dictionary but in file %s are 0x%lx!\n"
-					" Temporally corrected because DATA_DIR option to 0x%lx.\n",
-					space->flags, node->name, flags, space->flags);
+				ib::warn()
+					<< "Tablespace " << space_id
+					<< " flags " << space->flags
+					<< " in the data dictionary but in file " << node->name
+					<< " are " << flags
+					<< ". Temporally corrected because DATA_DIR option to "
+					<< space->flags;
 
 				flags = space->flags;
 			} else {
@@ -788,8 +778,7 @@ fil_node_open_file(
 				page, FSP_FREE_LIMIT);
 			ulint	free_len	= flst_get_len(
 				FSP_HEADER_OFFSET + FSP_FREE + page);
-			ut_ad(space->size_in_header == 0
-			      || space->size_in_header == size);
+
 			ut_ad(space->free_limit == 0
 			      || space->free_limit == free_limit);
 			ut_ad(space->free_len == 0
@@ -801,16 +790,35 @@ fil_node_open_file(
 
 		ut_free(buf2);
 
+#ifdef MYSQL_ENCRYPTION
+		/* For encrypted tablespace, we need to check the
+		encrytion key and iv(initial vector) is readed. */
+		if (FSP_FLAGS_GET_ENCRYPTION(flags)
+		    && !recv_recovery_is_on()) {
+			if (space->encryption_type != Encryption::AES) {
+				ib::error()
+					<< "Can't read encryption"
+					<< " key from file "
+					<< node->name << "!";
+				return(false);
+			}
+		}
+#endif
+
 		if (node->size == 0) {
 			ulint	extent_size;
 
 			extent_size = page_size.physical() * FSP_EXTENT_SIZE;
+
+			/* After apply-incremental, tablespaces are not extended
+			to a whole megabyte. Do not cut off valid data. */
+#ifndef UNIV_HOTBACKUP
 			/* Truncate the size to a multiple of extent size. */
 			if (size_bytes >= extent_size) {
 				size_bytes = ut_2pow_round(size_bytes,
 							   extent_size);
 			}
-
+#endif /* !UNIV_HOTBACKUP */
 			node->size = (ulint)
 				(size_bytes / page_size.physical());
 
@@ -896,20 +904,20 @@ fil_node_close_file(
 	}
 }
 
-/********************************************************************//**
-Tries to close a file in the LRU list. The caller must hold the fil_sys
+/** Tries to close a file in the LRU list. The caller must hold the fil_sys
 mutex.
 @return true if success, false if should retry later; since i/o's
 generally complete in < 100 ms, and as InnoDB writes at most 128 pages
 from the buffer pool in a batch, and then immediately flushes the
 files, there is a good chance that the next time we find a suitable
-node from the LRU list */
+node from the LRU list.
+ at param[in] print_info	if true, prints information why it
+			cannot close a file*/
 static
 bool
 fil_try_to_close_file_in_LRU(
-/*=========================*/
-	bool	print_info)	/*!< in: if true, prints information why it
-				cannot close a file */
+
+	bool	print_info)
 {
 	fil_node_t*	node;
 
@@ -1078,7 +1086,7 @@ fil_mutex_enter_and_prepare_for_io(
 		os_aio_simulated_wake_handler_threads();
 
 		os_thread_sleep(20000);
-#endif
+#endif /* !UNIV_HOTBACKUP */
 		/* Flush tablespaces so that we can close modified files in
 		the LRU list. */
 
@@ -1303,6 +1311,8 @@ fil_space_create(
 
 	UT_LIST_INIT(space->chain, &fil_node_t::chain);
 
+	/* This warning is not applicable while MEB scanning the redo logs */
+#ifndef UNIV_HOTBACKUP
 	if (fil_type_is_data(purpose)
 	    && !recv_recovery_on
 	    && id > fil_system->max_assigned_id) {
@@ -1317,16 +1327,20 @@ fil_space_create(
 
 		fil_system->max_assigned_id = id;
 	}
-
+#endif /* !UNIV_HOTBACKUP */
 	space->purpose = purpose;
 	space->flags = flags;
 
 	space->magic_n = FIL_SPACE_MAGIC_N;
 
+	space->encryption_type = Encryption::NONE;
+
 	rw_lock_create(fil_space_latch_key, &space->latch, SYNC_FSP);
 
 	if (space->purpose == FIL_TYPE_TEMPORARY) {
+#ifndef UNIV_HOTBACKUP
 		ut_d(space->latch.set_temp_fsp());
+#endif /* !UNIV_HOTBACKUP */
 	}
 
 	HASH_INSERT(fil_space_t, hash, fil_system->spaces, id, space);
@@ -1885,15 +1899,12 @@ fil_write_flushed_lsn(
 
 	if (err == DB_SUCCESS) {
 		mach_write_to_8(buf + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, lsn);
-
 		err = fil_write(page_id, univ_page_size, 0,
 				univ_page_size.physical(), buf);
-
 		fil_flush_file_spaces(FIL_TYPE_TABLESPACE);
 	}
 
 	ut_free(buf1);
-
 	return(err);
 }
 
@@ -1992,7 +2003,7 @@ fil_create_directory_for_tablename(
 	memcpy(path + len + 1, name, namend - name);
 	path[len + (namend - name) + 1] = 0;
 
-	os_normalize_path_for_win(path);
+	os_normalize_path(path);
 
 	bool	success = os_file_create_directory(path, false);
 	ut_a(success);
@@ -2000,7 +2011,6 @@ fil_create_directory_for_tablename(
 	ut_free(path);
 }
 
-#ifndef UNIV_HOTBACKUP
 /** Write a log record about an operation on a tablespace file.
 @param[in]	type		MLOG_FILE_NAME or MLOG_FILE_DELETE
 or MLOG_FILE_CREATE2 or MLOG_FILE_RENAME2
@@ -2080,7 +2090,7 @@ fil_op_write_log(
 		ut_ad(0);
 	}
 }
-
+#ifndef UNIV_HOTBACKUP
 /** Write redo log for renaming a file.
 @param[in]	space_id	tablespace id
 @param[in]	first_page_no	first page number in the file
@@ -2102,7 +2112,7 @@ fil_name_write_rename(
 		MLOG_FILE_RENAME2,
 		space_id, first_page_no, old_name, new_name, 0, mtr);
 }
-
+#endif /* !UNIV_HOTBACKUP */
 /** Write MLOG_FILE_NAME for a file.
 @param[in]	space_id	tablespace id
 @param[in]	first_page_no	first page number in the file
@@ -2119,7 +2129,6 @@ fil_name_write(
 	fil_op_write_log(
 		MLOG_FILE_NAME, space_id, first_page_no, name, NULL, 0, mtr);
 }
-
 /** Write MLOG_FILE_NAME for a file.
 @param[in]	space		tablespace
 @param[in]	first_page_no	first page number in the file
@@ -2135,8 +2144,8 @@ fil_name_write(
 {
 	fil_name_write(space->id, first_page_no, file->name, mtr);
 }
-#endif
 
+#ifndef UNIV_HOTBACKUP
 /********************************************************//**
 Recreates table indexes by applying
 TRUNCATE log record during recovery.
@@ -2377,7 +2386,7 @@ fil_recreate_tablespace(
 
 	return(err);
 }
-
+#endif /* UNIV_HOTBACKUP */
 /** Replay a file rename operation if possible.
 @param[in]	space_id	tablespace identifier
 @param[in]	first_page_no	first page number in the file
@@ -2440,15 +2449,10 @@ fil_op_replay_rename(
 	ut_free(dir);
 
 	/* New path must not exist. */
-	bool		exists;
-	os_file_type_t	ftype;
-
-	if (!os_file_status(new_name, &exists, &ftype)
-	    || exists) {
-		ib::error() << "Cannot replay rename '" << name
-			<< "' to '" << new_name << "'"
-			" for space ID " << space_id
-			<< " because the target file exists."
+	dberr_t		err = fil_rename_tablespace_check(
+		space_id, name, new_name, false);
+	if (err != DB_SUCCESS) {
+		ib::error() << " Cannot replay file rename."
 			" Remove either file and try again.";
 		return(false);
 	}
@@ -2839,6 +2843,7 @@ fil_delete_tablespace(
 	return(err);
 }
 
+#ifndef UNIV_HOTBACKUP
 /** Truncate the tablespace to needed size.
 @param[in]	space_id	id of tablespace to truncate
 @param[in]	size_in_pages	truncate size.
@@ -3027,9 +3032,8 @@ fil_space_is_redo_skipped(
 
 	return(is_redo_skipped);
 }
-#endif
+#endif /* UNIV_DEBUG */
 
-#ifndef UNIV_HOTBACKUP
 /*******************************************************************//**
 Discards a single-table tablespace. The tablespace must be cached in the
 memory cache. Discarding is like deleting a tablespace, but
@@ -3076,51 +3080,6 @@ fil_discard_tablespace(
 #endif /* !UNIV_HOTBACKUP */
 
 /*******************************************************************//**
-Renames the memory cache structures of a single-table tablespace.
- at return true if success */
-static
-bool
-fil_rename_tablespace_in_mem(
-/*=========================*/
-	fil_space_t*	space,	/*!< in: tablespace memory object */
-	fil_node_t*	node,	/*!< in: file node of that tablespace */
-	const char*	new_name,	/*!< in: new name */
-	const char*	new_path)	/*!< in: new file path */
-{
-	fil_space_t*	space2;
-	const char*	old_name	= space->name;
-
-	ut_ad(mutex_own(&fil_system->mutex));
-
-	space2 = fil_space_get_by_name(old_name);
-	if (space != space2) {
-		ib::error() << "Cannot find " << old_name
-			<< " in tablespace memory cache";
-		return(false);
-	}
-
-	space2 = fil_space_get_by_name(new_name);
-	if (space2 != NULL) {
-		ib::error() << new_name
-			<< " is already in tablespace memory cache";
-
-		return(false);
-	}
-
-	HASH_DELETE(fil_space_t, name_hash, fil_system->name_hash,
-		    ut_fold_string(space->name), space);
-	ut_free(space->name);
-	ut_free(node->name);
-
-	space->name = mem_strdup(new_name);
-	node->name = mem_strdup(new_path);
-
-	HASH_INSERT(fil_space_t, name_hash, fil_system->name_hash,
-		    ut_fold_string(space->name), space);
-	return(true);
-}
-
-/*******************************************************************//**
 Allocates and builds a file name from a path, a table or tablespace name
 and a suffix. The string must be freed by caller with ut_free().
 @param[in] path NULL or the direcory path or the full path and filename.
@@ -3224,6 +3183,47 @@ fil_make_filepath(
 	return(full_name);
 }
 
+/** Test if a tablespace file can be renamed to a new filepath by checking
+if that the old filepath exists and the new filepath does not exist.
+ at param[in]	space_id	tablespace id
+ at param[in]	old_path	old filepath
+ at param[in]	new_path	new filepath
+ at param[in]	is_discarded	whether the tablespace is discarded
+ at return innodb error code */
+dberr_t
+fil_rename_tablespace_check(
+	ulint		space_id,
+	const char*	old_path,
+	const char*	new_path,
+	bool		is_discarded)
+{
+	bool	exists = false;
+	os_file_type_t	ftype;
+
+	if (!is_discarded
+	    && os_file_status(old_path, &exists, &ftype)
+	    && !exists) {
+		ib::error() << "Cannot rename '" << old_path
+			<< "' to '" << new_path
+			<< "' for space ID " << space_id
+			<< " because the source file"
+			<< " does not exist.";
+		return(DB_TABLESPACE_NOT_FOUND);
+	}
+
+	exists = false;
+	if (!os_file_status(new_path, &exists, &ftype) || exists) {
+		ib::error() << "Cannot rename '" << old_path
+			<< "' to '" << new_path
+			<< "' for space ID " << space_id
+			<< " because the target file exists."
+			" Remove the target file and try again.";
+		return(DB_TABLESPACE_EXISTS);
+	}
+
+	return(DB_SUCCESS);
+}
+
 /** Rename a single-table tablespace.
 The tablespace must exist in the memory cache.
 @param[in]	id		tablespace identifier
@@ -3245,22 +3245,16 @@ fil_rename_tablespace(
 	fil_space_t*	space;
 	fil_node_t*	node;
 	ulint		count		= 0;
-	char*		old_name	= NULL;
-	const char*	new_path	= new_path_in;
 	ut_a(id != 0);
 
-	if (new_path == NULL) {
-		new_path = fil_make_filepath(NULL, new_name, IBD, false);
-	}
-
 	ut_ad(strchr(new_name, '/') != NULL);
-	ut_ad(strchr(new_path, OS_PATH_SEPARATOR) != NULL);
 retry:
 	count++;
 
 	if (!(count % 1000)) {
-		ib::warn() << "Cannot rename " << old_path << " to "
-			<< new_path << ", retried " << count << " times."
+		ib::warn() << "Cannot rename file " << old_path
+			<< " (space id " << id << "), retried " << count
+			<< " times."
 			" There are either pending IOs or flushes or"
 			" the file is being extended.";
 	}
@@ -3269,8 +3263,6 @@ fil_rename_tablespace(
 
 	space = fil_space_get_by_id(id);
 
-	bool success = false;
-
 	DBUG_EXECUTE_IF("fil_rename_tablespace_failure_1", space = NULL; );
 
 	if (space == NULL) {
@@ -3278,11 +3270,25 @@ fil_rename_tablespace(
 			<< " in the tablespace memory cache, though the file '"
 			<< old_path
 			<< "' in a rename operation should have that id.";
+func_exit:
+		mutex_exit(&fil_system->mutex);
+		return(false);
+	}
 
+	if (count > 25000) {
+		space->stop_ios = false;
+		goto func_exit;
+	}
+	if (space != fil_space_get_by_name(space->name)) {
+		ib::error() << "Cannot find " << space->name
+			<< " in tablespace memory cache";
+		space->stop_ios = false;
 		goto func_exit;
 	}
 
-	if (count > 25000) {
+	if (fil_space_get_by_name(new_name)) {
+		ib::error() << new_name
+			<< " is already in tablespace memory cache";
 		space->stop_ios = false;
 		goto func_exit;
 	}
@@ -3305,21 +3311,18 @@ fil_rename_tablespace(
 		currently being extended, sleep for a while and
 		retry */
 		sleep = true;
-
 	} else if (node->modification_counter > node->flush_counter) {
 		/* Flush the space */
 		sleep = flush = true;
-
 	} else if (node->is_open) {
 		/* Close the file */
 
 		fil_node_close_file(node);
 	}
 
-	if (sleep) {
-
-		mutex_exit(&fil_system->mutex);
+	mutex_exit(&fil_system->mutex);
 
+	if (sleep) {
 		os_thread_sleep(20000);
 
 		if (flush) {
@@ -3329,56 +3332,83 @@ fil_rename_tablespace(
 		sleep = flush = false;
 		goto retry;
 	}
+	ut_ad(space->stop_ios);
+	char*	new_file_name = new_path_in == NULL
+		? fil_make_filepath(NULL, new_name, IBD, false)
+		: mem_strdup(new_path_in);
+	char*	old_file_name = node->name;
+	char*	new_space_name = mem_strdup(new_name);
+	char*	old_space_name = space->name;
+	ulint	old_fold = ut_fold_string(old_space_name);
+	ulint	new_fold = ut_fold_string(new_space_name);
+
+	ut_ad(strchr(old_file_name, OS_PATH_SEPARATOR) != NULL);
+	ut_ad(strchr(new_file_name, OS_PATH_SEPARATOR) != NULL);
+#ifndef UNIV_HOTBACKUP
+	if (!recv_recovery_on) {
+		mtr_t		mtr;
 
-	old_name = mem_strdup(space->name);
+		mtr.start();
+		fil_name_write_rename(
+			id, 0, old_file_name, new_file_name, &mtr);
+		mtr.commit();
+		log_mutex_enter();
+	}
+#endif /* !UNIV_HOTBACKUP */
 
-	/* Rename the tablespace and the node in the memory cache */
-	success = fil_rename_tablespace_in_mem(
-		space, node, new_name, new_path);
+	/* log_sys->mutex is above fil_system->mutex in the latching order */
+	ut_ad(log_mutex_own());
+	mutex_enter(&fil_system->mutex);
+	ut_ad(space->name == old_space_name);
+	/* We already checked these. */
+	ut_ad(space == fil_space_get_by_name(old_space_name));
+	ut_ad(!fil_space_get_by_name(new_space_name));
+	ut_ad(node->name == old_file_name);
 
-	if (success) {
+	bool	success;
 
-		DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
-			goto skip_second_rename; );
+	DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
+			goto skip_rename; );
 
-		success = os_file_rename(
-			innodb_data_file_key, old_path, new_path);
+	success = os_file_rename(
+		innodb_data_file_key, old_file_name, new_file_name);
 
-		DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
-skip_second_rename:
-			success = false; );
+	DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
+			skip_rename: success = false; );
 
-		if (!success) {
-			/* We have to revert the changes we made
-			to the tablespace memory cache */
+	ut_ad(node->name == old_file_name);
 
-			bool	reverted = fil_rename_tablespace_in_mem(
-				space, node, old_name, old_path);
-
-			ut_a(reverted);
-		}
+	if (success) {
+		node->name = new_file_name;
 	}
 
-	ut_free(old_name);
-	space->stop_ios = false;
-
-func_exit:
-	mutex_exit(&fil_system->mutex);
-
 #ifndef UNIV_HOTBACKUP
-	if (success && !recv_recovery_on) {
-		mtr_t		mtr;
-
-		mtr_start(&mtr);
-		fil_name_write_rename(id, 0, old_path, new_path, &mtr);
-		mtr_commit(&mtr);
+	if (!recv_recovery_on) {
+		log_mutex_exit();
 	}
 #endif /* !UNIV_HOTBACKUP */
 
-	if (new_path != new_path_in) {
-		ut_free(const_cast<char*>(new_path));
+	ut_ad(space->name == old_space_name);
+	if (success) {
+		HASH_DELETE(fil_space_t, name_hash, fil_system->name_hash,
+			    old_fold, space);
+		space->name = new_space_name;
+		HASH_INSERT(fil_space_t, name_hash, fil_system->name_hash,
+			    new_fold, space);
+	} else {
+		/* Because nothing was renamed, we must free the new
+		names, not the old ones. */
+		old_file_name = new_file_name;
+		old_space_name = new_space_name;
 	}
 
+	ut_ad(space->stop_ios);
+	space->stop_ios = false;
+	mutex_exit(&fil_system->mutex);
+
+	ut_free(old_file_name);
+	ut_free(old_space_name);
+
 	return(success);
 }
 
@@ -3388,8 +3418,10 @@ fil_rename_tablespace(
 For general tablespaces, the 'dbname/' part may be missing.
 @param[in]	path		Path and filename of the datafile to create.
 @param[in]	flags		Tablespace flags
- at param[in]	size		Initial size of the tablespace file in pages,
-must be >= FIL_IBD_FILE_INITIAL_SIZE
+ at param[in]	size		Initial size of the tablespace file in
+                                pages, must be >= FIL_IBD_FILE_INITIAL_SIZE
+ at param[in]	mode		MariaDB encryption mode
+ at param[in]	key_id		MariaDB encryption key_id
 @return DB_SUCCESS or error code */
 dberr_t
 fil_ibd_create(
@@ -3398,8 +3430,8 @@ fil_ibd_create(
 	const char*	path,
 	ulint		flags,
 	ulint		size,
-	fil_encryption_t mode,	/*!< in: encryption mode */
-	ulint		key_id) /*!< in: encryption key_id */
+	fil_encryption_t mode,
+	ulint		key_id)
 {
 	os_file_t	file;
 	dberr_t		err;
@@ -3411,7 +3443,7 @@ fil_ibd_create(
 	bool		has_shared_space = FSP_FLAGS_GET_SHARED(flags);
 	fil_space_t*	space = NULL;
 	fil_space_crypt_t *crypt_data = NULL;
- 
+
 	ut_ad(!is_system_tablespace(space_id));
 	ut_ad(!srv_read_only_mode);
 	ut_a(space_id < SRV_LOG_SPACE_FIRST_ID);
@@ -3547,10 +3579,11 @@ fil_ibd_create(
 	page = static_cast<byte*>(ut_align(buf2, UNIV_PAGE_SIZE));
 
 	memset(page, '\0', UNIV_PAGE_SIZE);
-
+#ifndef UNIV_HOTBACKUP
 	/* Add the UNIV_PAGE_SIZE to the table flags and write them to the
 	tablespace header. */
 	flags = fsp_flags_set_page_size(flags, univ_page_size);
+#endif /* !UNIV_HOTBACKUP */
 	fsp_header_init_fields(page, space_id, flags);
 	mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id);
 
@@ -3570,7 +3603,6 @@ fil_ibd_create(
 
 	} else {
 		page_zip_des_t	page_zip;
-
 		page_zip_set_size(&page_zip, page_size.physical());
 		page_zip.data = page + UNIV_PAGE_SIZE;
 #ifdef UNIV_DEBUG
@@ -3616,6 +3648,9 @@ fil_ibd_create(
 		return(DB_ERROR);
 	}
 
+	/* MEB creates isl files during copy-back, hence they
+	should not be created during apply log operation. */
+#ifndef UNIV_HOTBACKUP
 	if (has_data_dir || has_shared_space) {
 		/* Make the ISL file if the IBD file is not
 		in the default location. */
@@ -3627,6 +3662,7 @@ fil_ibd_create(
 			return(err);
 		}
 	}
+#endif /* !UNIV_HOTBACKUP */
 
 	/* Create crypt data if the tablespace is either encrypted or user has
 	requested it to remain unencrypted. */
@@ -3636,15 +3672,31 @@ fil_ibd_create(
 	}
 
 	space = fil_space_create(name, space_id, flags, is_temp
-				 ? FIL_TYPE_TEMPORARY : FIL_TYPE_TABLESPACE, crypt_data);
+		? FIL_TYPE_TEMPORARY : FIL_TYPE_TABLESPACE,
+		crypt_data);
 
 	if (!fil_node_create_low(
 			path, size, space, false, punch_hole, atomic_write)) {
 
+		if (crypt_data) {
+			free(crypt_data);
+		}
+
 		err = DB_ERROR;
 		goto error_exit_1;
 	}
 
+#ifdef MYSQL_ENCRYPTION
+	/* For encryption tablespace, initial encryption information. */
+	if (FSP_FLAGS_GET_ENCRYPTION(space->flags)) {
+		err = fil_set_encryption(space->id,
+					 Encryption::AES,
+					 NULL,
+					 NULL);
+		ut_ad(err == DB_SUCCESS);
+	}
+#endif /* MYSQL_ENCRYPTION */
+
 #ifndef UNIV_HOTBACKUP
 	if (!is_temp) {
 		mtr_t			mtr;
@@ -3657,7 +3709,7 @@ fil_ibd_create(
 		fil_name_write(space, 0, file, &mtr);
 		mtr_commit(&mtr);
 	}
-#endif
+#endif /* !UNIV_HOTBACKUP */
 	err = DB_SUCCESS;
 
 	/* Error code is set.  Cleanup the various variables used.
@@ -3715,18 +3767,20 @@ fil_ibd_open(
 	ulint		flags,
 	const char*	space_name,
 	const char*	path_in,
-	dict_table_t* table)
+	dict_table_t*	table)
 {
 	dberr_t		err = DB_SUCCESS;
 	bool		dict_filepath_same_as_default = false;
 	bool		link_file_found = false;
 	bool		link_file_is_bad = false;
 	bool		is_shared = FSP_FLAGS_GET_SHARED(flags);
+	bool		is_encrypted = FSP_FLAGS_GET_ENCRYPTION(flags);
 	Datafile	df_default;	/* default location */
 	Datafile	df_dict;	/* dictionary location */
 	RemoteDatafile	df_remote;	/* remote location */
 	ulint		tablespaces_found = 0;
 	ulint		valid_tablespaces_found = 0;
+	bool		for_import = (purpose == FIL_TYPE_IMPORT);
 
 	ut_ad(!fix_dict || rw_lock_own(dict_operation_lock, RW_LOCK_X));
 
@@ -3778,7 +3832,6 @@ fil_ibd_open(
 		if (table) {
 			table->crypt_data = df_remote.get_crypt_info();
 		}
-
 	} else if (df_remote.filepath() != NULL) {
 		/* An ISL file was found but contained a bad filepath in it.
 		Better validate anything we do find. */
@@ -3793,7 +3846,6 @@ fil_ibd_open(
 			/* Dict path is not the default path. Always validate
 			remote files. If default is opened, it was moved. */
 			validate = true;
-
 			df_dict.set_filepath(path_in);
 			if (df_dict.open_read_only(true) == DB_SUCCESS) {
 				ut_ad(df_dict.is_open());
@@ -3839,7 +3891,6 @@ fil_ibd_open(
 
 #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
 	if (!srv_use_doublewrite_buf && df_default.is_open()) {
-
 		atomic_write = fil_fusionio_enable_atomic_write(
 			df_default.handle());
 	} else {
@@ -3852,31 +3903,46 @@ fil_ibd_open(
 	/*  We have now checked all possible tablespace locations and
 	have a count of how many unique files we found.  If things are
 	normal, we only found 1. */
-	if (!validate && tablespaces_found == 1) {
+	/* For encrypted tablespace, we need to check the
+	encryption in header of first page. */
+	if (!validate && tablespaces_found == 1 && !is_encrypted) {
 		goto skip_validate;
 	}
 
 	/* Read and validate the first page of these three tablespace
 	locations, if found. */
 	valid_tablespaces_found +=
-		(df_remote.validate_to_dd(id, flags) == DB_SUCCESS) ? 1 : 0;
+		(df_remote.validate_to_dd(id, flags, for_import)
+			== DB_SUCCESS) ? 1 : 0;
 
 	valid_tablespaces_found +=
-		(df_default.validate_to_dd(id, flags) == DB_SUCCESS) ? 1 : 0;
+		(df_default.validate_to_dd(id, flags, for_import)
+			== DB_SUCCESS) ? 1 : 0;
 
 	valid_tablespaces_found +=
-		(df_dict.validate_to_dd(id, flags) == DB_SUCCESS) ? 1 : 0;
+		(df_dict.validate_to_dd(id, flags, for_import)
+			== DB_SUCCESS) ? 1 : 0;
 
 	/* Make sense of these three possible locations.
 	First, bail out if no tablespace files were found. */
 	if (valid_tablespaces_found == 0) {
-		/* The following call prints an error message */
-		os_file_get_last_error(true);
-		ib::error() << "Could not find a valid tablespace file for `"
-			<< space_name << "`. " << TROUBLESHOOT_DATADICT_MSG;
+		if (!is_encrypted) {
+			/* The following call prints an error message.
+			For encrypted tablespace we skip print, since it should
+			be keyring plugin issues. */
+			os_file_get_last_error(true);
+			ib::error() << "Could not find a valid tablespace file for `"
+				<< space_name << "`. " << TROUBLESHOOT_DATADICT_MSG;
+		}
 
 		return(DB_CORRUPTION);
 	}
+	if (!validate && !is_encrypted) {
+		return(DB_SUCCESS);
+	}
+	if (validate && is_encrypted && fil_space_get(id)) {
+		return(DB_SUCCESS);
+	}
 
 	/* Do not open any tablespaces if more than one tablespace with
 	the correct space ID and flags were found. */
@@ -4024,10 +4090,10 @@ fil_ibd_open(
 skip_validate:
 	if (err == DB_SUCCESS) {
 		fil_space_t*	space = fil_space_create(
-		      space_name, id, flags, purpose,
-			    df_remote.is_open() ? df_remote.get_crypt_info() :
-			    df_dict.is_open() ? df_dict.get_crypt_info() :
-			    df_default.get_crypt_info());
+			space_name, id, flags, purpose,
+			df_remote.is_open() ? df_remote.get_crypt_info() :
+			df_dict.is_open() ? df_dict.get_crypt_info() :
+			df_default.get_crypt_info());
 
 		/* We do not measure the size of the file, that is why
 		we pass the 0 below */
@@ -4037,9 +4103,27 @@ fil_ibd_open(
 			    df_dict.is_open() ? df_dict.filepath() :
 			    df_default.filepath(), 0, space, false,
 			    true, atomic_write) == NULL) {
-
 			err = DB_ERROR;
 		}
+
+#ifdef MYSQL_ENCRYPTION
+		/* For encryption tablespace, initialize encryption
+		information.*/
+		if (err == DB_SUCCESS && is_encrypted && !for_import) {
+			Datafile& df_current = df_remote.is_open() ?
+				df_remote: df_dict.is_open() ?
+				df_dict : df_default;
+
+			byte*	key = df_current.m_encryption_key;
+			byte*	iv = df_current.m_encryption_iv;
+			ut_ad(key && iv);
+
+			err = fil_set_encryption(space->id, Encryption::AES,
+						 key, iv);
+			ut_ad(err == DB_SUCCESS);
+		}
+#endif /* MYSQL_ENCRYPTION */
+
 	}
 
 	return(err);
@@ -4296,7 +4380,6 @@ fil_ibd_discover(
 	/* A datafile was not discovered for the filename given. */
 	return(false);
 }
-
 /** Open an ibd tablespace and add it to the InnoDB data structures.
 This is similar to fil_ibd_open() except that it is used while processing
 the REDO log, so the data dictionary is not available and very little
@@ -4327,14 +4410,17 @@ fil_ibd_load(
 		filename from the first node of the tablespace we opened
 		previously. Fail if it is different. */
 		fil_node_t* node = UT_LIST_GET_FIRST(space->chain);
-
 		if (0 != strcmp(innobase_basename(filename),
 				innobase_basename(node->name))) {
-			ib::info() << "Ignoring data file '" << filename
+#ifdef  UNIV_HOTBACKUP
+			ib::trace()
+#else
+			ib::info()
+#endif /* UNIV_HOTBACKUP */
+				<< "Ignoring data file '" << filename
 				<< "' with space ID " << space->id
 				<< ". Another data file called " << node->name
 				<< " exists with the same space ID.";
-
 				space = NULL;
 				return(FIL_LOAD_ID_CHANGED);
 		}
@@ -4345,7 +4431,6 @@ fil_ibd_load(
 	under the datadir, then just try to open it there. */
 	Datafile	file;
 	file.set_filepath(filename);
-
 	Folder		folder(filename, dirname_length(filename));
 	if (folder_mysql_datadir >= folder) {
 		file.open_read_only(false);
@@ -4367,7 +4452,12 @@ fil_ibd_load(
 		os_offset_t	minimum_size;
 	case DB_SUCCESS:
 		if (file.space_id() != space_id) {
-			ib::info() << "Ignoring data file '"
+#ifdef UNIV_HOTBACKUP
+			ib::trace()
+#else /* !UNIV_HOTBACKUP */
+			ib::info()
+#endif /* UNIV_HOTBACKUP */
+				<< "Ignoring data file '"
 				<< file.filepath()
 				<< "' with space ID " << file.space_id()
 				<< ", since the redo log references "
@@ -4375,7 +4465,6 @@ fil_ibd_load(
 				<< space_id << ".";
 			return(FIL_LOAD_ID_CHANGED);
 		}
-
 		/* Get and test the file size. */
 		size = os_file_get_size(file.handle());
 
@@ -4390,7 +4479,6 @@ fil_ibd_load(
 			ib::error() << "Could not measure the size of"
 				" single-table tablespace file '"
 				<< file.filepath() << "'";
-
 		} else if (size < minimum_size) {
 #ifndef UNIV_HOTBACKUP
 			ib::error() << "The size of tablespace file '"
@@ -4411,6 +4499,12 @@ fil_ibd_load(
 		/* Fall through to error handling */
 
 	case DB_TABLESPACE_EXISTS:
+#ifdef UNIV_HOTBACKUP
+		if (file.flags() == ~(ulint)0) {
+			return FIL_LOAD_OK;
+		}
+#endif /* UNIV_HOTBACKUP */
+
 		return(FIL_LOAD_INVALID);
 
 	default:
@@ -4499,6 +4593,21 @@ fil_ibd_load(
 		ut_error;
 	}
 
+#ifdef MYSQL_ENCRYPTION
+	/* For encryption tablespace, initial encryption information. */
+	if (FSP_FLAGS_GET_ENCRYPTION(space->flags)
+	    && file.m_encryption_key != NULL) {
+		dberr_t err = fil_set_encryption(space->id,
+						 Encryption::AES,
+						 file.m_encryption_key,
+						 file.m_encryption_iv);
+		if (err != DB_SUCCESS) {
+			ib::error() << "Can't set encryption information for"
+				" tablespace " << space->name << "!";
+		}
+	}
+#endif /* MYSQL_ENCRYPTION */
+
 	return(FIL_LOAD_OK);
 }
 
@@ -4556,6 +4665,7 @@ fil_report_missing_tablespace(
 		" exists in the InnoDB internal data dictionary.";
 }
 
+#ifndef UNIV_HOTBACKUP
 /** Returns true if a matching tablespace exists in the InnoDB tablespace
 memory cache. Note that if we have not done a crash recovery at the database
 startup, there may be many tablespaces which are not yet in the memory cache.
@@ -4567,6 +4677,7 @@ error log if a matching tablespace is not found from memory.
 @param[in]	adjust_space	Whether to adjust space id on mismatch
 @param[in]	heap		Heap memory
 @param[in]	table_id	table id
+ at param[in]	table		table
 @return true if a matching tablespace exists in the memory cache */
 bool
 fil_space_for_table_exists_in_mem(
@@ -4633,7 +4744,6 @@ fil_space_for_table_exists_in_mem(
 			/* Found */
 
 			mutex_exit(&fil_system->mutex);
-
 			return(true);
 		}
 	}
@@ -4732,7 +4842,7 @@ fil_space_for_table_exists_in_mem(
 
 	return(false);
 }
-
+#endif /* !UNIV_HOTBACKUP */
 /** Return the space ID based on the tablespace name.
 The tablespace must be found in the tablespace memory cache.
 This call is made from external to this module, so the mutex is not owned.
@@ -4787,7 +4897,7 @@ fil_write_zeros(
 	while (offset < end) {
 
 #ifdef UNIV_HOTBACKUP
-		err = = os_file_write(
+		err = os_file_write(
 			request, node->name, node->handle, buf, offset,
 			n_bytes);
 #else
@@ -4828,6 +4938,16 @@ fil_space_extend(
 	ut_ad(!srv_read_only_mode || fsp_is_system_temporary(space->id));
 
 retry:
+
+#ifdef UNIV_HOTBACKUP
+	page_size_t	page_length(space->flags);
+	ulint   actual_size = space->size;
+	ib::trace() << "space id : " << space->id << ", space name : "
+		<< space->name << ", space size : " << actual_size << " pages,"
+		<< " desired space size : " << size << " pages,"
+		<< " page size : " << page_length.physical();
+#endif /* UNIV_HOTBACKUP */
+
 	bool		success = true;
 
 	fil_mutex_enter_and_prepare_for_io(space->id);
@@ -4905,14 +5025,12 @@ fil_space_extend(
 
 		len = ((node->size + n_node_extend) * page_size) - node_start;
 		ut_ad(len > 0);
+		const char* name = node->name == NULL ? space->name : node->name;
 
 #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
 		/* This is required by FusionIO HW/Firmware */
 		int	ret = posix_fallocate(node->handle, node_start, len);
 
-		const char* name = node->name == NULL ? space->name : node->name;
-
-
 		/* We already pass the valid offset and len in, if EINVAL
 		is returned, it could only mean that the file system doesn't
 		support fallocate(), currently one known case is
@@ -4922,7 +5040,7 @@ fil_space_extend(
 			ib::error()
 				<< "posix_fallocate(): Failed to preallocate"
 				" data for file "
-				<< node->name << ", desired size "
+				<< name << ", desired size "
 				<< len << " bytes."
 				" Operating system error number "
 				<< ret << ". Check"
@@ -4951,7 +5069,7 @@ fil_space_extend(
 
 				ib::warn()
 					<< "Error while writing " << len
-					<< " zeroes to " << node->name
+					<< " zeroes to " << name
 					<< " starting at offset " << node_start;
 			}
 		}
@@ -4991,6 +5109,10 @@ fil_space_extend(
 	} else if (space->id == srv_tmp_space.space_id()) {
 		srv_tmp_space.set_last_file_size(size_in_pages);
 	}
+#else
+	ib::trace() << "extended space : " << space->name << " from "
+		<< actual_size << " pages to " << space->size << " pages "
+		<< ", desired space size : " << size << " pages.";
 #endif /* !UNIV_HOTBACKUP */
 
 	mutex_exit(&fil_system->mutex);
@@ -5016,7 +5138,7 @@ fil_extend_tablespaces_to_stored_len(void)
 	dberr_t		error;
 	bool		success;
 
-	buf = ut_malloc_nokey(UNIV_PAGE_SIZE);
+	buf = (byte*)ut_malloc_nokey(UNIV_PAGE_SIZE);
 
 	mutex_enter(&fil_system->mutex);
 
@@ -5273,6 +5395,33 @@ fil_report_invalid_page_access(
 	_exit(1);
 }
 
+#ifdef MYSQL_ENCRYPTION
+/** Set encryption information for IORequest.
+ at param[in,out]	req_type	IO request
+ at param[in]	page_id		page id
+ at param[in]	space		table space */
+inline
+void
+fil_io_set_encryption(
+	IORequest&		req_type,
+	const page_id_t&	page_id,
+	fil_space_t*		space)
+{
+	/* Don't encrypt the log, page 0 of all tablespaces, all pages
+	from the system tablespace. */
+	if (!req_type.is_log() && page_id.page_no() > 0
+	    && space->encryption_type != Encryption::NONE)
+	{
+		req_type.encryption_key(space->encryption_key,
+					space->encryption_klen,
+					space->encryption_iv);
+		req_type.encryption_algorithm(Encryption::AES);
+	} else {
+		req_type.clear_encrypted();
+	}
+}
+#endif /* MYSQL_ENCRYPTION */
+
 /** Reads or writes data. This operation could be asynchronous (aio).
 
 @param[in,out] type	IO context
@@ -5289,7 +5438,8 @@ fil_report_invalid_page_access(
 			aligned
 @param[in] message	message for aio handler if non-sync aio
 			used, else ignored
-
+ at param[in] write_size	actual payload size when written
+                        to avoid extra punch holes in compression
 @return DB_SUCCESS, DB_TABLESPACE_DELETED or DB_TABLESPACE_TRUNCATED
 	if we are trying to do i/o on a tablespace which does not exist */
 dberr_t
@@ -5355,9 +5505,10 @@ fil_io(
 	}
 #else /* !UNIV_HOTBACKUP */
 	ut_a(sync);
-	mode = OS_AIO_SYNC;
+	ulint mode = OS_AIO_SYNC;
 #endif /* !UNIV_HOTBACKUP */
 
+#ifndef UNIV_HOTBACKUP
 	if (req_type.is_read()) {
 
 		srv_stats.data_read.add(len);
@@ -5369,6 +5520,7 @@ fil_io(
 
 		srv_stats.data_written.add(len);
 	}
+#endif /* !UNIV_HOTBACKUP */
 
 	/* Reserve the fil_system mutex and make sure that we can open at
 	least one file while holding it, if the file is not already open */
@@ -5434,7 +5586,7 @@ fil_io(
 			    && UT_LIST_GET_LEN(space->chain) == 1
 			    && (srv_is_tablespace_truncated(space->id)
 				|| space->is_being_truncated
-				|| srv_was_tablespace_truncated(space->id))
+				|| srv_was_tablespace_truncated(space))
 			    && req_type.is_read()) {
 
 				/* Handle page which is outside the truncated
@@ -5541,6 +5693,7 @@ fil_io(
 
 	const char* name = node->name == NULL ? space->name : node->name;
 
+#ifdef MYSQL_COMPRESSION
 	/* Don't compress the log, page 0 of all tablespaces, tables
 	compresssed with the old scheme and all pages from the system
 	tablespace. */
@@ -5561,6 +5714,12 @@ fil_io(
 	} else {
 		req_type.clear_compressed();
 	}
+#endif /* MYSQL_COMPRESSION */
+
+#ifdef MYSQL_ENCRYPTION
+	/* Set encryption information. */
+	fil_io_set_encryption(req_type, page_id, space);
+#endif /* MYSQL_ENCRYPTION */
 
 	req_type.block_size(node->block_size);
 
@@ -5580,14 +5739,14 @@ fil_io(
 		err = os_file_write(
 			req_type, node->name, node->handle, buf, offset, len);
 	}
-#else
+#else /* UNIV_HOTBACKUP */
 	/* Queue the aio request */
 	err = os_aio(
 		req_type,
-		mode, node->name, node->handle, buf, offset, len,
+		mode, name, node->handle, buf, offset, len,
 		fsp_is_system_temporary(page_id.space())
 		? false : srv_read_only_mode,
-		node, message, NULL);
+		node, message, write_size);
 
 #endif /* UNIV_HOTBACKUP */
 
@@ -5599,7 +5758,7 @@ fil_io(
 
 			ib::warn()
 				<< "Punch hole failed for '"
-				<< node->name << "'";
+				<< name << "'";
 		}
 
 		fil_no_punch_hole(node);
@@ -5689,7 +5848,7 @@ fil_aio_wait(
 
 	ut_ad(0);
 }
-#endif /* UNIV_HOTBACKUP */
+#endif /* !UNIV_HOTBACKUP */
 
 /**********************************************************************//**
 Flushes to disk possible writes cached by the OS. If the space does not exist
@@ -5777,7 +5936,9 @@ fil_flush(
 			not know what bugs OS's may contain in file
 			i/o */
 
+#ifndef UNIV_HOTBACKUP
 			int64_t	sig_count = os_event_reset(node->sync_event);
+#endif /* !UNIV_HOTBACKUP */
 
 			mutex_exit(&fil_system->mutex);
 
@@ -6020,6 +6181,7 @@ fil_page_set_type(
 	mach_write_to_2(page + FIL_PAGE_TYPE, type);
 }
 
+#ifndef UNIV_HOTBACKUP
 /** Reset the page type.
 Data files created before MySQL 5.1 may contain garbage in FIL_PAGE_TYPE.
 In MySQL 3.23.53, only undo log pages and index pages were tagged.
@@ -6040,6 +6202,7 @@ fil_page_reset_type(
 		<< fil_page_get_type(page) << " to " << type << ".";
 	mlog_write_ulint(page + FIL_PAGE_TYPE, type, MLOG_2BYTES, mtr);
 }
+#endif /* !UNIV_HOTBACKUP */
 
 /****************************************************************//**
 Closes the tablespace memory cache. */
@@ -6047,20 +6210,23 @@ void
 fil_close(void)
 /*===========*/
 {
-	hash_table_free(fil_system->spaces);
+	if (fil_system) {
+		hash_table_free(fil_system->spaces);
 
-	hash_table_free(fil_system->name_hash);
+		hash_table_free(fil_system->name_hash);
 
-	ut_a(UT_LIST_GET_LEN(fil_system->LRU) == 0);
-	ut_a(UT_LIST_GET_LEN(fil_system->unflushed_spaces) == 0);
-	ut_a(UT_LIST_GET_LEN(fil_system->space_list) == 0);
+		ut_a(UT_LIST_GET_LEN(fil_system->LRU) == 0);
+		ut_a(UT_LIST_GET_LEN(fil_system->unflushed_spaces) == 0);
+		ut_a(UT_LIST_GET_LEN(fil_system->space_list) == 0);
 
-	mutex_free(&fil_system->mutex);
+		mutex_free(&fil_system->mutex);
 
-	ut_free(fil_system);
-	fil_system = NULL;
+		ut_free(fil_system);
+		fil_system = NULL;
+	}
 }
 
+#ifndef UNIV_HOTBACKUP
 /********************************************************************//**
 Initializes a buffer control block when the buf_pool is created. */
 static
@@ -6092,8 +6258,10 @@ struct fil_iterator_t {
 	ulint		n_io_buffers;		/*!< Number of pages to use
 						for IO */
 	byte*		io_buffer;		/*!< Buffer to use for IO */
-	fil_space_crypt_t *crypt_data;		/*!< Crypt data (if encrypted) */
-	byte*           crypt_io_buffer;        /*!< IO buffer when encrypted */
+	fil_space_crypt_t *crypt_data;		/*!< MariaDB Crypt data (if encrypted) */
+	byte*           crypt_io_buffer;        /*!< MariaDB IO buffer when encrypted */
+	byte*		encryption_key;		/*!< Encryption key */
+	byte*		encryption_iv;		/*!< Encryption iv */
 };
 
 /********************************************************************//**
@@ -6166,9 +6334,19 @@ fil_iterate(
 		ut_ad(n_bytes > 0);
 		ut_ad(!(n_bytes % iter.page_size));
 
-		dberr_t		err;
+		dberr_t		err = DB_SUCCESS;
 		IORequest	read_request(read_type);
 
+#ifdef MYSQL_ENCRYPTION
+		/* For encrypted table, set encryption information. */
+		if (iter.encryption_key != NULL && offset != 0) {
+			read_request.encryption_key(iter.encryption_key,
+						    ENCRYPTION_KEY_LEN,
+						    iter.encryption_iv);
+			read_request.encryption_algorithm(Encryption::AES);
+		}
+#endif /* MYSQL_ENCRYPTION */
+
 		byte* readptr = io_buffer;
 		byte* writeptr = io_buffer;
 		bool encrypted = false;
@@ -6206,8 +6384,9 @@ fil_iterate(
 
 			ulint page_type = mach_read_from_2(src+FIL_PAGE_TYPE);
 
-			bool page_compressed = (page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED ||
-				page_type == FIL_PAGE_PAGE_COMPRESSED);
+			bool page_compressed =
+				(page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
+				 || page_type == FIL_PAGE_PAGE_COMPRESSED);
 
 			/* If tablespace is encrypted, we need to decrypt
 			the page. */
@@ -6303,6 +6482,16 @@ fil_iterate(
 
 		IORequest	write_request(write_type);
 
+#ifdef MYSQL_ENCRYPTION
+		/* For encrypted table, set encryption information. */
+		if (iter.encryption_key != NULL && offset != 0) {
+			write_request.encryption_key(iter.encryption_key,
+						     ENCRYPTION_KEY_LEN,
+						     iter.encryption_iv);
+			write_request.encryption_algorithm(Encryption::AES);
+		}
+#endif /* MYSQL_ENCRYPTION */
+
 		/* A page was updated in the set, write back to disk.
 		Note: We don't have the compression algorithm, we write
 		out the imported file as uncompressed. */
@@ -6451,34 +6640,58 @@ fil_tablespace_iterate(
 		iter.crypt_data = fil_space_read_crypt_data(
 			0, page, crypt_data_offset);
 
-		/* Compressed pages can't be optimised for block IO for now.
-		We do the IMPORT page by page. */
-
-		if (callback.get_page_size().is_compressed()) {
-			iter.n_io_buffers = 1;
-			ut_a(iter.page_size
-			     == callback.get_page_size().physical());
+#ifdef MYSQL_ENCRYPTION
+		/* Set encryption info. */
+		iter.encryption_key = table->encryption_key;
+		iter.encryption_iv = table->encryption_iv;
+
+		/* Check encryption is matched or not. */
+		ulint	space_flags = callback.get_space_flags();
+		if (FSP_FLAGS_GET_ENCRYPTION(space_flags)) {
+			ut_ad(table->encryption_key != NULL);
+
+			if (!dict_table_is_encrypted(table)) {
+				ib::error() << "Table is not in an encrypted"
+					" tablespace, but the data file which"
+					" trying to import is an encrypted"
+					" tablespace";
+				err = DB_IO_NO_ENCRYPT_TABLESPACE;
+			}
 		}
+#endif /* MYSQL_ENCRYPTION */
 
-		/** Add an extra page for compressed page scratch area. */
+		if (err == DB_SUCCESS) {
 
-		void*	io_buffer = ut_malloc_nokey(
-			(2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
+			/* Compressed pages can't be optimised for block IO
+			for now.  We do the IMPORT page by page. */
 
-		iter.io_buffer = static_cast<byte*>(
-			ut_align(io_buffer, UNIV_PAGE_SIZE));
+			if (callback.get_page_size().is_compressed()) {
+				iter.n_io_buffers = 1;
+				ut_a(iter.page_size
+				     == callback.get_page_size().physical());
+			}
 
-		void* crypt_io_buffer = NULL;
-		if (iter.crypt_data != NULL) {
-			crypt_io_buffer = ut_malloc_nokey(
-				iter.n_io_buffers * UNIV_PAGE_SIZE);
-			iter.crypt_io_buffer = static_cast<byte*>(
-				crypt_io_buffer);
-		}
+			/** Add an extra page for compressed page scratch
+			area. */
+			void*	io_buffer = ut_malloc_nokey(
+				(2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
+
+			iter.io_buffer = static_cast<byte*>(
+				ut_align(io_buffer, UNIV_PAGE_SIZE));
+
+			/** Add an exta buffer for encryption */
+			void* crypt_io_buffer = NULL;
+			if (iter.crypt_data != NULL) {
+				crypt_io_buffer = ut_malloc_nokey(
+					iter.n_io_buffers * UNIV_PAGE_SIZE);
+				iter.crypt_io_buffer = static_cast<byte*>(
+					crypt_io_buffer);
+			}
 
-		err = fil_iterate(iter, block, callback);
+			err = fil_iterate(iter, block, callback);
 
-		ut_free(io_buffer);
+			ut_free(io_buffer);
+		}
 	}
 
 	if (err == DB_SUCCESS) {
@@ -6504,6 +6717,7 @@ fil_tablespace_iterate(
 
 	return(err);
 }
+#endif /* !UNIV_HOTBACKUP */
 
 /** Set the tablespace table size.
 @param[in]	page	a page belonging to the tablespace */
@@ -6526,7 +6740,6 @@ fil_delete_file(
 	/* Force a delete of any stale .ibd files that are lying around. */
 
 	ib::info() << "Deleting " << ibd_filepath;
-
 	os_file_delete_if_exists(innodb_data_file_key, ibd_filepath, NULL);
 
 	char*	cfg_filepath = fil_make_filepath(
@@ -6583,6 +6796,7 @@ fil_get_space_names(
 	return(err);
 }
 
+#ifndef UNIV_HOTBACKUP
 /** Return the next fil_node_t in the current or next fil_space_t.
 Once started, the caller must keep calling this until it returns NULL.
 fil_space_acquire() and fil_space_release() are invoked here which
@@ -6644,51 +6858,100 @@ fil_node_next(
 @param[in]	new_table	new table
 @param[in]	tmp_name	temporary table name
 @param[in,out]	mtr		mini-transaction
- at return	whether the operation succeeded */
-bool
+ at return innodb error code */
+dberr_t
 fil_mtr_rename_log(
 	const dict_table_t*	old_table,
 	const dict_table_t*	new_table,
 	const char*		tmp_name,
 	mtr_t*			mtr)
 {
+	dberr_t	err;
+
+	bool	old_is_file_per_table =
+		!is_system_tablespace(old_table->space)
+		&& !DICT_TF_HAS_SHARED_SPACE(old_table->flags);
+
+	bool	new_is_file_per_table =
+		!is_system_tablespace(new_table->space)
+		&& !DICT_TF_HAS_SHARED_SPACE(new_table->flags);
+
+	/* If neither table is file-per-table,
+	there will be no renaming of files. */
+	if (!old_is_file_per_table && !new_is_file_per_table) {
+		return(DB_SUCCESS);
+	}
+
 	const char*	old_dir = DICT_TF_HAS_DATA_DIR(old_table->flags)
 		? old_table->data_dir_path
 		: NULL;
-	const char*	new_dir = DICT_TF_HAS_DATA_DIR(new_table->flags)
-		? new_table->data_dir_path
-		: NULL;
-
-	char*		old_path = fil_make_filepath(
-		new_dir, old_table->name.m_name, IBD, false);
-	char*		new_path = fil_make_filepath(
-		new_dir, new_table->name.m_name, IBD, false);
-	char*		tmp_path = fil_make_filepath(
-		old_dir, tmp_name, IBD, false);
 
-	if (!old_path || !new_path || !tmp_path) {
-		ut_free(old_path);
-		ut_free(new_path);
-		ut_free(tmp_path);
-		return(false);
+	char*	old_path = fil_make_filepath(
+		old_dir, old_table->name.m_name, IBD, (old_dir != NULL));
+	if (old_path == NULL) {
+		return(DB_OUT_OF_MEMORY);
 	}
 
-	if (!is_system_tablespace(old_table->space)) {
+	if (old_is_file_per_table) {
+		char*	tmp_path = fil_make_filepath(
+			old_dir, tmp_name, IBD, (old_dir != NULL));
+		if (tmp_path == NULL) {
+			ut_free(old_path);
+			return(DB_OUT_OF_MEMORY);
+		}
+
+		/* Temp filepath must not exist. */
+		err = fil_rename_tablespace_check(
+			old_table->space, old_path, tmp_path,
+			dict_table_is_discarded(old_table));
+		if (err != DB_SUCCESS) {
+			ut_free(old_path);
+			ut_free(tmp_path);
+			return(err);
+		}
+
 		fil_name_write_rename(
 			old_table->space, 0, old_path, tmp_path, mtr);
+
+		ut_free(tmp_path);
 	}
 
-	if (!is_system_tablespace(new_table->space)) {
+	if (new_is_file_per_table) {
+		const char*	new_dir = DICT_TF_HAS_DATA_DIR(new_table->flags)
+			? new_table->data_dir_path
+			: NULL;
+		char*	new_path = fil_make_filepath(
+				new_dir, new_table->name.m_name,
+				IBD, (new_dir != NULL));
+		if (new_path == NULL) {
+			ut_free(old_path);
+			return(DB_OUT_OF_MEMORY);
+		}
+
+		/* Destination filepath must not exist unless this ALTER
+		TABLE starts and ends with a file_per-table tablespace. */
+		if (!old_is_file_per_table) {
+			err = fil_rename_tablespace_check(
+				new_table->space, new_path, old_path,
+				dict_table_is_discarded(new_table));
+			if (err != DB_SUCCESS) {
+				ut_free(old_path);
+				ut_free(new_path);
+				return(err);
+			}
+		}
+
 		fil_name_write_rename(
 			new_table->space, 0, new_path, old_path, mtr);
+
+		ut_free(new_path);
 	}
 
 	ut_free(old_path);
-	ut_free(new_path);
-	ut_free(tmp_path);
-	return(true);
-}
 
+	return(DB_SUCCESS);
+}
+#endif /* !UNIV_HOTBACKUP */
 #ifdef UNIV_DEBUG
 /** Check that a tablespace is valid for mtr_commit().
 @param[in]	space	persistent tablespace that has been changed */
@@ -6770,13 +7033,13 @@ fil_names_dirty_and_write(
 	DBUG_EXECUTE_IF("fil_names_write_bogus",
 			{
 				char bogus_name[] = "./test/bogus file.ibd";
-				os_normalize_path_for_win(bogus_name);
+				os_normalize_path(bogus_name);
 				fil_name_write(
 					SRV_LOG_SPACE_FIRST_ID, 0,
 					bogus_name, mtr);
 			});
 }
-
+#ifndef UNIV_HOTBACKUP
 /** On a log checkpoint, reset fil_names_dirty_and_write() flags
 and write out MLOG_FILE_NAME and MLOG_CHECKPOINT if needed.
 @param[in]	lsn		checkpoint LSN
@@ -6948,6 +7211,7 @@ truncate_t::truncate(
 
 	return(err);
 }
+#endif /* !UNIV_HOTBACKUP */
 
 /**
 Note that the file system where the file resides doesn't support PUNCH HOLE.
@@ -6959,18 +7223,28 @@ fil_no_punch_hole(fil_node_t* node)
 	node->punch_hole = false;
 }
 
-/** Set the compression type for the tablespace
- at param[in] space		Space ID of tablespace for which to set
- at param[in] algorithm		Text representation of the algorithm
+#ifdef MYSQL_COMPRESSION_ENCRYPTION
+
+/** Set the compression type for the tablespace of a table
+ at param[in]	table		The table that should be compressed
+ at param[in]	algorithm	Text representation of the algorithm
 @return DB_SUCCESS or error code */
 dberr_t
 fil_set_compression(
-	ulint		space_id,
+	dict_table_t*	table,
 	const char*	algorithm)
 {
-	ut_ad(!is_system_or_undo_tablespace(space_id));
+	ut_ad(table != NULL);
 
-	if (is_shared_tablespace(space_id)) {
+	/* We don't support Page Compression for the system tablespace,
+	the temporary tablespace, or any general tablespace because
+	COMPRESSION is set by TABLE DDL, not TABLESPACE DDL. There is
+	no other technical reason.  Also, do not use it for missing
+	tables or tables with compressed row_format. */
+	if (table->ibd_file_missing
+	    || !DICT_TF2_FLAG_IS_SET(table, DICT_TF2_USE_FILE_PER_TABLE)
+	    || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY)
+	    || page_size_t(table->flags).is_compressed()) {
 
 		return(DB_IO_NO_PUNCH_HOLE_TABLESPACE);
 	}
@@ -6983,17 +7257,20 @@ fil_set_compression(
 #ifndef UNIV_DEBUG
 		compression.m_type = Compression::NONE;
 #else
-		compression.m_type = static_cast<Compression::Type>(
-			srv_debug_compress);
-
-		switch (compression.m_type) {
+		/* This is a Debug tool for setting compression on all
+		compressible tables not otherwise specified. */
+		switch (srv_debug_compress) {
 		case Compression::LZ4:
-		case Compression::NONE:
 		case Compression::ZLIB:
+		case Compression::NONE:
+
+			compression.m_type =
+				static_cast<Compression::Type>(
+					srv_debug_compress);
 			break;
 
 		default:
-			ut_error;
+			compression.m_type = Compression::NONE;
 		}
 
 #endif /* UNIV_DEBUG */
@@ -7003,31 +7280,25 @@ fil_set_compression(
 	} else {
 
 		err = Compression::check(algorithm, &compression);
-
-		ut_ad(err == DB_SUCCESS || err == DB_UNSUPPORTED);
 	}
 
-	fil_space_t*	space = fil_space_get(space_id);
+	fil_space_t*	space = fil_space_get(table->space);
 
 	if (space == NULL) {
+		return(DB_NOT_FOUND);
+	}
 
-		err = DB_NOT_FOUND;
-
-	} else {
-
-		space->compression_type = compression.m_type;
+	space->compression_type = compression.m_type;
 
-		if (space->compression_type != Compression::NONE
-		    && err == DB_SUCCESS) {
+	if (space->compression_type != Compression::NONE) {
 
-			const fil_node_t* node;
+		const fil_node_t* node;
 
-			node = UT_LIST_GET_FIRST(space->chain);
+		node = UT_LIST_GET_FIRST(space->chain);
 
-			if (!node->punch_hole) {
+		if (!node->punch_hole) {
 
-				return(DB_IO_NO_PUNCH_HOLE_FS);
-			}
+			return(DB_IO_NO_PUNCH_HOLE_FS);
 		}
 	}
 
@@ -7046,6 +7317,102 @@ fil_get_compression(
 	return(space == NULL ? Compression::NONE : space->compression_type);
 }
 
+/** Set the encryption type for the tablespace
+ at param[in] space_id		Space ID of tablespace for which to set
+ at param[in] algorithm		Encryption algorithm
+ at param[in] key			Encryption key
+ at param[in] iv			Encryption iv
+ at return DB_SUCCESS or error code */
+dberr_t
+fil_set_encryption(
+	ulint			space_id,
+	Encryption::Type	algorithm,
+	byte*			key,
+	byte*			iv)
+{
+	ut_ad(!is_system_or_undo_tablespace(space_id));
+
+	if (is_system_tablespace(space_id)) {
+		return(DB_IO_NO_ENCRYPT_TABLESPACE);
+	}
+
+	mutex_enter(&fil_system->mutex);
+
+	fil_space_t*	space = fil_space_get_by_id(space_id);
+
+	if (space == NULL) {
+		mutex_exit(&fil_system->mutex);
+		return(DB_NOT_FOUND);
+	}
+
+	ut_ad(algorithm != Encryption::NONE);
+	space->encryption_type = algorithm;
+	if (key == NULL) {
+		Encryption::random_value(space->encryption_key);
+	} else {
+		memcpy(space->encryption_key,
+		       key, ENCRYPTION_KEY_LEN);
+	}
+
+	space->encryption_klen = ENCRYPTION_KEY_LEN;
+	if (iv == NULL) {
+		Encryption::random_value(space->encryption_iv);
+	} else {
+		memcpy(space->encryption_iv,
+		       iv, ENCRYPTION_KEY_LEN);
+	}
+
+	mutex_exit(&fil_system->mutex);
+
+	return(DB_SUCCESS);
+}
+
+/** Rotate the tablespace keys by new master key.
+ at return true if the re-encrypt suceeds */
+bool
+fil_encryption_rotate()
+{
+	fil_space_t*	space;
+	mtr_t		mtr;
+	byte		encrypt_info[ENCRYPTION_INFO_SIZE_V2];
+
+	for (space = UT_LIST_GET_FIRST(fil_system->space_list);
+	     space != NULL; ) {
+		/* Skip unencypted tablespaces. */
+		if (is_system_or_undo_tablespace(space->id)
+		    || fsp_is_system_temporary(space->id)
+		    || space->purpose == FIL_TYPE_LOG) {
+			space = UT_LIST_GET_NEXT(space_list, space);
+			continue;
+		}
+
+		if (space->encryption_type != Encryption::NONE) {
+			mtr_start(&mtr);
+			mtr.set_named_space(space->id);
+
+			space = mtr_x_lock_space(space->id, &mtr);
+
+			memset(encrypt_info, 0, ENCRYPTION_INFO_SIZE_V2);
+
+			if (!fsp_header_rotate_encryption(space,
+							  encrypt_info,
+							  &mtr)) {
+				mtr_commit(&mtr);
+				return(false);
+			}
+
+			mtr_commit(&mtr);
+		}
+
+		space = UT_LIST_GET_NEXT(space_list, space);
+		DBUG_EXECUTE_IF("ib_crash_during_rotation_for_encryption",
+				DBUG_SUICIDE(););
+	}
+
+	return(true);
+}
+#endif /* MYSQL_COMPRESSION_ENCRYPTION */
+
 /** Build the basic folder name from the path and length provided
 @param[in]	path	pathname (may also include the file basename)
 @param[in]	len	length of the path, in bytes */
@@ -7203,6 +7570,7 @@ test_make_filepath()
 	path = MF("/this/is/a/path/with/a/filename", NULL, IBD, false); DISPLAY;
 	path = MF("/this/is/a/path/with/a/filename", NULL, ISL, false); DISPLAY;
 	path = MF("/this/is/a/path/with/a/filename", NULL, CFG, false); DISPLAY;
+	path = MF("/this/is/a/path/with/a/filename", NULL, CFP, false); DISPLAY;
 	path = MF("/this/is/a/path/with/a/filename.ibd", NULL, IBD, false); DISPLAY;
 	path = MF("/this/is/a/path/with/a/filename.ibd", NULL, IBD, false); DISPLAY;
 	path = MF("/this/is/a/path/with/a/filename.dat", NULL, IBD, false); DISPLAY;
@@ -7212,6 +7580,7 @@ test_make_filepath()
 	path = MF(NULL, "dbname/tablespacename", IBD, false); DISPLAY;
 	path = MF(NULL, "dbname/tablespacename", ISL, false); DISPLAY;
 	path = MF(NULL, "dbname/tablespacename", CFG, false); DISPLAY;
+	path = MF(NULL, "dbname/tablespacename", CFP, false); DISPLAY;
 	path = MF(NULL, "dbname\\tablespacename", NO_EXT, false); DISPLAY;
 	path = MF(NULL, "dbname\\tablespacename", IBD, false); DISPLAY;
 	path = MF("/this/is/a/path", "dbname/tablespacename", IBD, false); DISPLAY;
@@ -7226,6 +7595,43 @@ test_make_filepath()
 #endif /* UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH */
 /* @} */
 
+/** Release the reserved free extents.
+ at param[in]	n_reserved	number of reserved extents */
+void
+fil_space_t::release_free_extents(ulint	n_reserved)
+{
+	ut_ad(rw_lock_own(&latch, RW_LOCK_X));
+
+	ut_a(n_reserved_extents >= n_reserved);
+	n_reserved_extents -= n_reserved;
+}
+
+/******************************************************************
+Get crypt data for a tablespace */
+UNIV_INTERN
+fil_space_crypt_t*
+fil_space_get_crypt_data(
+/*=====================*/
+	ulint id)	/*!< in: space id */
+{
+	fil_space_t*	space;
+	fil_space_crypt_t* crypt_data = NULL;
+
+	ut_ad(fil_system);
+
+	mutex_enter(&fil_system->mutex);
+
+	space = fil_space_get_by_id(id);
+
+	if (space != NULL) {
+		crypt_data = space->crypt_data;
+	}
+
+	mutex_exit(&fil_system->mutex);
+
+	return(crypt_data);
+}
+
 /*******************************************************************//**
 Increments the count of pending operation, if space is not being deleted.
 @return	TRUE if being deleted, and operation should be skipped */
@@ -7293,33 +7699,7 @@ fil_decr_pending_ops(
 }
 
 /******************************************************************
-Get crypt data for a tablespace */
-UNIV_INTERN
-fil_space_crypt_t*
-fil_space_get_crypt_data(
-/*=====================*/
-	ulint id)	/*!< in: space id */
-{
-	fil_space_t*	space;
-	fil_space_crypt_t* crypt_data = NULL;
-
-	ut_ad(fil_system);
-
-	mutex_enter(&fil_system->mutex);
-
-	space = fil_space_get_by_id(id);
-
-	if (space != NULL) {
-		crypt_data = space->crypt_data;
-	}
-
-	mutex_exit(&fil_system->mutex);
-
-	return(crypt_data);
-}
-
-/******************************************************************
-Get crypt data for a tablespace */
+Set crypt data for a tablespace */
 UNIV_INTERN
 fil_space_crypt_t*
 fil_space_set_crypt_data(
diff --git a/storage/innobase/fsp/fsp0file.cc b/storage/innobase/fsp/fsp0file.cc
index b3e85c5..501a8e5 100644
--- a/storage/innobase/fsp/fsp0file.cc
+++ b/storage/innobase/fsp/fsp0file.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, 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
@@ -33,8 +33,11 @@ Created 2013-7-26 by Kevin Lewis
 #include "srv0start.h"
 #include "ut0new.h"
 #include "fil0crypt.h"
+#ifdef UNIV_HOTBACKUP
+#include "my_sys.h"
+#endif /* UNIV_HOTBACKUP */
 
-/** Initialize the name and flags of this datafile.
+/** Initialize the name, size and order of this datafile
 @param[in]	name	tablespace name, will be copied
 @param[in]	flags	tablespace flags */
 void
@@ -47,6 +50,8 @@ Datafile::init(
 
 	m_name = mem_strdup(name);
 	m_flags = flags;
+	m_encryption_key = NULL;
+	m_encryption_iv = NULL;
 }
 
 /** Release the resources. */
@@ -60,10 +65,20 @@ Datafile::shutdown()
 
 	free_filepath();
 
+	if (m_encryption_key != NULL) {
+		ut_free(m_encryption_key);
+		m_encryption_key = NULL;
+	}
+
 	if (m_crypt_info) {
 		fil_space_destroy_crypt_data(&m_crypt_info);
 	}
 
+	if (m_encryption_iv != NULL) {
+		ut_free(m_encryption_iv);
+		m_encryption_iv = NULL;
+	}
+
 	free_first_page();
 }
 
@@ -380,13 +395,15 @@ Datafile::free_first_page()
 space ID and flags.  The file should exist and be successfully opened
 in order for this function to validate it.
 @param[in]	space_id	The expected tablespace ID.
- at param[in]	flags	The expected tablespace flags.
+ at param[in]	flags		The expected tablespace flags.
+ at param[in]	for_import	if it is for importing
 @retval DB_SUCCESS if tablespace is valid, DB_ERROR if not.
 m_is_valid is also set true on success, else false. */
 dberr_t
 Datafile::validate_to_dd(
-	ulint	space_id,
-	ulint	flags)
+	ulint		space_id,
+	ulint		flags,
+	bool		for_import)
 {
 	dberr_t err;
 
@@ -397,7 +414,7 @@ Datafile::validate_to_dd(
 	/* Validate this single-table-tablespace with the data dictionary,
 	but do not compare the DATA_DIR flag, in case the tablespace was
 	remotely located. */
-	err = validate_first_page();
+	err = validate_first_page(0, for_import);
 	if (err != DB_SUCCESS) {
 		return(err);
 	}
@@ -441,14 +458,52 @@ Datafile::validate_for_recovery()
 	ut_ad(is_open());
 	ut_ad(!srv_read_only_mode);
 
-	err = validate_first_page();
+	err = validate_first_page(0, false);
 
 	switch (err) {
 	case DB_SUCCESS:
 	case DB_TABLESPACE_EXISTS:
+#ifdef UNIV_HOTBACKUP
+		err = restore_from_doublewrite(0);
+		if (err != DB_SUCCESS) {
+			return(err);
+		}
+		/* Free the previously read first page and then re-validate. */
+		free_first_page();
+		err = validate_first_page(0, false);
+		if (err == DB_SUCCESS) {
+			std::string filepath = fil_space_get_first_path(
+				m_space_id);
+			if (is_intermediate_file(filepath.c_str())) {
+				/* Existing intermediate file with same space
+				id is obsolete.*/
+				if (fil_space_free(m_space_id, FALSE)) {
+					err = DB_SUCCESS;
+				}
+		} else {
+			filepath.assign(m_filepath);
+			if (is_intermediate_file(filepath.c_str())) {
+				/* New intermediate file with same space id
+				shall be ignored.*/
+				err = DB_TABLESPACE_EXISTS;
+				/* Set all bits of 'flags' as a special
+				indicator for "ignore tablespace". Hopefully
+				InnoDB will never use all bits or at least all
+				bits set will not be a meaningful setting
+				otherwise.*/
+				m_flags = ~0;
+			}
+		}
+		}
+#endif /* UNIV_HOTBACKUP */
 		break;
 
 	default:
+		/* For encryption tablespace, we skip the retry step,
+		since it is only because the keyring is not ready. */
+		if (FSP_FLAGS_GET_ENCRYPTION(m_flags)) {
+			return(err);
+		}
 		/* Re-open the file in read-write mode  Attempt to restore
 		page 0 from doublewrite and read the space ID from a survey
 		of the first few pages. */
@@ -476,7 +531,7 @@ Datafile::validate_for_recovery()
 
 		/* Free the previously read first page and then re-validate. */
 		free_first_page();
-		err = validate_first_page();
+		err = validate_first_page(0, false);
 	}
 
 	if (err == DB_SUCCESS) {
@@ -491,12 +546,14 @@ tablespace is opened.  This occurs before the fil_space_t is created
 so the Space ID found here must not already be open.
 m_is_valid is set true on success, else false.
 @param[out]	flush_lsn	contents of FIL_PAGE_FILE_FLUSH_LSN
+ at param[in]	for_import	if it is for importing
 (only valid for the first file of the system tablespace)
 @retval DB_SUCCESS on if the datafile is valid
 @retval DB_CORRUPTION if the datafile is not readable
 @retval DB_TABLESPACE_EXISTS if there is a duplicate space_id */
 dberr_t
-Datafile::validate_first_page(lsn_t* flush_lsn)
+Datafile::validate_first_page(lsn_t*	flush_lsn,
+			      bool	for_import)
 {
 	char*		prev_name;
 	char*		prev_filepath;
@@ -585,6 +642,51 @@ Datafile::validate_first_page(lsn_t* flush_lsn)
 
 	}
 
+#ifdef MYSQL_ENCRYPTION
+	/* For encrypted tablespace, check the encryption info in the
+	first page can be decrypt by master key, otherwise, this table
+	can't be open. And for importing, we skip checking it. */
+	if (FSP_FLAGS_GET_ENCRYPTION(m_flags) && !for_import) {
+		m_encryption_key = static_cast<byte*>(
+			ut_zalloc_nokey(ENCRYPTION_KEY_LEN));
+		m_encryption_iv = static_cast<byte*>(
+			ut_zalloc_nokey(ENCRYPTION_KEY_LEN));
+#ifdef	UNIV_ENCRYPT_DEBUG
+                fprintf(stderr, "Got from file %lu:", m_space_id);
+#endif
+		if (!fsp_header_get_encryption_key(m_flags,
+						   m_encryption_key,
+						   m_encryption_iv,
+						   m_first_page)) {
+			ib::error()
+				<< "Encryption information in"
+				<< " datafile: " << m_filepath
+				<< " can't be decrypted"
+				<< " , please confirm the keyfile"
+				<< " is match and keyring plugin"
+				<< " is loaded.";
+
+			m_is_valid = false;
+			free_first_page();
+			ut_free(m_encryption_key);
+			ut_free(m_encryption_iv);
+			m_encryption_key = NULL;
+			m_encryption_iv = NULL;
+			return(DB_CORRUPTION);
+		}
+
+		if (recv_recovery_is_on()
+		    && memcmp(m_encryption_key,
+			      m_encryption_iv,
+			      ENCRYPTION_KEY_LEN) == 0) {
+			ut_free(m_encryption_key);
+			ut_free(m_encryption_iv);
+			m_encryption_key = NULL;
+			m_encryption_iv = NULL;
+		}
+	}
+#endif /* MYSQL_ENCRYPTION */
+
 	if (fil_space_read_name_and_filepath(
 		m_space_id, &prev_name, &prev_filepath)) {
 
@@ -988,13 +1090,11 @@ RemoteDatafile::create_link_file(
 	} else {
 		link_filepath = fil_make_filepath(NULL, name, ISL, false);
 	}
-
 	if (link_filepath == NULL) {
 		return(DB_ERROR);
 	}
 
 	prev_filepath = read_link_file(link_filepath);
-
 	if (prev_filepath) {
 		/* Truncate will call this with an existing
 		link file which contains the same filepath. */
@@ -1007,14 +1107,15 @@ RemoteDatafile::create_link_file(
 	}
 
 	/** Check if the file already exists. */
-	FILE*                   file = NULL;
-	bool                    exists;
-	os_file_type_t          ftype;
+	FILE*			file = NULL;
+	bool			exists;
+	os_file_type_t		ftype;
 
 	success = os_file_status(link_filepath, &exists, &ftype);
 	ulint error = 0;
 
 	if (success && !exists) {
+
 		file = fopen(link_filepath, "w");
 		if (file == NULL) {
 			/* This call will print its own error message */
@@ -1025,6 +1126,7 @@ RemoteDatafile::create_link_file(
 	}
 
 	if (error != 0) {
+
 		ib::error() << "Cannot create file " << link_filepath << ".";
 
 		if (error == OS_FILE_ALREADY_EXISTS) {
@@ -1050,7 +1152,7 @@ RemoteDatafile::create_link_file(
 		error = os_file_get_last_error(true);
 		ib::error() <<
 			"Cannot write link file: "
-			<< filepath;
+			    << link_filepath << " filepath: " << filepath;
 		err = DB_ERROR;
 	}
 
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index 109299a..9dc99f3 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -31,30 +31,29 @@ Created 11/29/1995 Heikki Tuuri
 #include "fsp0fsp.ic"
 #endif
 
+#ifdef UNIV_HOTBACKUP
+# include "fut0lst.h"
+#else /* UNIV_HOTBACKUP */
 #include "buf0buf.h"
 #include "fil0fil.h"
 #include "fil0crypt.h"
 #include "mtr0log.h"
 #include "ut0byte.h"
 #include "page0page.h"
-#include "page0zip.h"
-#ifdef UNIV_HOTBACKUP
-# include "fut0lst.h"
-#else /* UNIV_HOTBACKUP */
-# include "fut0fut.h"
-# include "srv0srv.h"
-# include "srv0start.h"
-# include "ibuf0ibuf.h"
-# include "btr0btr.h"
-# include "btr0sea.h"
-# include "dict0boot.h"
-# include "log0log.h"
-#endif /* UNIV_HOTBACKUP */
-#include "dict0mem.h"
+#include "fut0fut.h"
+#include "srv0srv.h"
+#include "srv0start.h"
+#include "ibuf0ibuf.h"
+#include "btr0btr.h"
+#include "btr0sea.h"
+#include "dict0boot.h"
+#include "log0log.h"
 #include "fsp0sysspace.h"
+#include "dict0mem.h"
 #include "fsp0types.h"
 
-#ifndef UNIV_HOTBACKUP
+// JAN: MySQL 5.7 Encryption
+// #include <my_aes.h>
 
 /** Returns an extent to the free list of a space.
 @param[in]	page_id		page id in the extent
@@ -148,7 +147,7 @@ fseg_alloc_free_page_low(
 	, ibool			has_done_reservation
 #endif /* UNIV_DEBUG */
 )
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Gets a pointer to the space header and x-locks its page.
 @param[in]	id		space id
@@ -205,6 +204,7 @@ fsp_flags_to_dict_tf(
 	bool	page_compressed = FSP_FLAGS_GET_PAGE_COMPRESSION(fsp_flags);
 	ulint	comp_level	= FSP_FLAGS_GET_PAGE_COMPRESSION_LEVEL(fsp_flags);
 	bool	atomic_writes	= FSP_FLAGS_GET_ATOMIC_WRITES(fsp_flags);
+
 	/* FSP_FLAGS_GET_TEMPORARY(fsp_flags) does not have an equivalent
 	flag position in the table flags. But it would go into flags2 if
 	any code is created where that is needed. */
@@ -215,6 +215,7 @@ fsp_flags_to_dict_tf(
 
 	return(flags);
 }
+#endif /* !UNIV_HOTBACKUP */
 
 /** Validate the tablespace flags.
 These flags are stored in the tablespace header at offset FSP_SPACE_FLAGS.
@@ -234,11 +235,17 @@ fsp_flags_is_valid(
 	bool	has_data_dir = FSP_FLAGS_HAS_DATA_DIR(flags);
 	bool	is_shared = FSP_FLAGS_GET_SHARED(flags);
 	bool	is_temp = FSP_FLAGS_GET_TEMPORARY(flags);
+	bool	is_encryption = FSP_FLAGS_GET_ENCRYPTION(flags);
 	ulint	unused = FSP_FLAGS_GET_UNUSED(flags);
 	bool	page_compression = FSP_FLAGS_GET_PAGE_COMPRESSION(flags);
 	ulint	page_compression_level = FSP_FLAGS_GET_PAGE_COMPRESSION_LEVEL(flags);
 	ulint	atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(flags);
 
+	const char *file;
+	ulint line;
+
+#define GOTO_ERROR file = __FILE__; line = __LINE__; goto err_exit;
+
 	DBUG_EXECUTE_IF("fsp_flags_is_valid_failure", return(false););
 
 	/* The Antelope row formats REDUNDANT and COMPACT did
@@ -254,60 +261,55 @@ fsp_flags_is_valid(
 	and externally stored parts. So if it is Post_antelope, it uses
 	Atomic BLOBs. */
 	if (post_antelope != atomic_blobs) {
-		fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted atomic_blobs %d\n",
-				flags, atomic_blobs);
+		GOTO_ERROR;
 		return(false);
 	}
 
 	/* Make sure there are no bits that we do not know about. */
 	if (unused != 0) {
-		fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted unused %lu\n",
-			flags, unused);
-		return(false);
+		GOTO_ERROR;
 	}
 
 	/* The zip ssize can be zero if it is other than compressed row format,
 	or it could be from 1 to the max. */
 	if (zip_ssize > PAGE_ZIP_SSIZE_MAX) {
-		fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted zip_ssize %lu max %d\n",
-			flags, zip_ssize, PAGE_ZIP_SSIZE_MAX);
-		return(false);
+		GOTO_ERROR;
 	}
 
 	/* The actual page size must be within 4k and 16K (3 =< ssize =< 5). */
 	if (page_ssize != 0
 	    && (page_ssize < UNIV_PAGE_SSIZE_MIN
 	        || page_ssize > UNIV_PAGE_SSIZE_MAX)) {
-		fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted page_ssize %lu min:%lu:max:%lu\n",
-			flags, page_ssize, UNIV_PAGE_SSIZE_MIN, UNIV_PAGE_SSIZE_MAX);
-		return(false);
+		GOTO_ERROR;
 	}
 
 	/* Only single-table tablespaces use the DATA DIRECTORY clause.
 	It is not compatible with the TABLESPACE clause.  Nor is it
 	compatible with the TEMPORARY clause. */
 	if (has_data_dir && (is_shared || is_temp)) {
-		fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted has_data_dir %d is_shared %d is_temp %d\n",
-			flags, has_data_dir, is_shared, is_temp);
+		GOTO_ERROR;
 		return(false);
 	}
 
+	/* Only single-table and not temp tablespaces use the encryption
+	clause. */
+	if (is_encryption && (is_shared || is_temp)) {
+		GOTO_ERROR;
+	}
+
 	/* Page compression level requires page compression and atomic blobs
 	to be set */
-        if (page_compression_level || page_compression) {
+	if (page_compression_level || page_compression) {
 		if (!page_compression || !atomic_blobs) {
-			fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted page_compression %d\n"
-				"InnoDB: Error: page_compression_level %lu atomic_blobs %d\n",
-				flags, page_compression, page_compression_level, atomic_blobs);
-			return(false);
+			GOTO_ERROR;
 		}
 	}
 
 	if (atomic_writes > ATOMIC_WRITES_OFF) {
-		fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted atomic_writes %lu\n",
-			flags, atomic_writes);
+		GOTO_ERROR;
 		return (false);
 	}
+
 #if UNIV_FORMAT_MAX != UNIV_FORMAT_B
 # error UNIV_FORMAT_MAX != UNIV_FORMAT_B, Add more validations.
 #endif
@@ -316,6 +318,24 @@ fsp_flags_is_valid(
 #endif
 
 	return(true);
+
+err_exit:
+	ib::error() << "Tablespace flags: " << flags << " corrupted "
+		    << " in file: " << file << " line: " << line
+		    << " post_antelope: " << post_antelope
+		    << " atomic_blobs: " << atomic_blobs
+		    << " unused: " << unused
+		    << " zip_ssize: " << zip_ssize << " max: " << PAGE_ZIP_SSIZE_MAX
+		    << " page_ssize: " << page_ssize
+		    << " " << UNIV_PAGE_SSIZE_MIN << ":" << UNIV_PAGE_SSIZE_MAX
+		    << " has_data_dir: " << has_data_dir
+		    << " is_shared: " << is_shared
+		    << " is_temp: " << is_temp
+		    << " is_encryption: " << is_encryption
+		    << " page_compressed: " << page_compression
+		    << " page_compression_level: " << page_compression_level
+		    << " atomic_writes: " << atomic_writes;
+	return (false);
 }
 
 /** Check if tablespace is system temporary.
@@ -351,6 +371,7 @@ fsp_is_file_per_table(
 		&& !fsp_is_shared_tablespace(fsp_flags));
 }
 
+#ifndef UNIV_HOTBACKUP
 #ifdef UNIV_DEBUG
 
 /** Skip some of the sanity checks that are time consuming even in debug mode
@@ -588,7 +609,7 @@ xdes_init(
 the same as the tablespace header
 @return pointer to the extent descriptor, NULL if the page does not
 exist in the space or if the offset exceeds free limit */
-UNIV_INLINE MY_ATTRIBUTE((nonnull(1,4), warn_unused_result))
+UNIV_INLINE MY_ATTRIBUTE((warn_unused_result))
 xdes_t*
 xdes_get_descriptor_with_space_hdr(
 	fsp_header_t*	sp_header,
@@ -883,6 +904,202 @@ fsp_header_init_fields(
 }
 
 #ifndef UNIV_HOTBACKUP
+/** Get the offset of encrytion information in page 0.
+ at param[in]	page_size	page size.
+ at return	offset on success, otherwise 0. */
+static
+ulint
+fsp_header_get_encryption_offset(
+	const page_size_t&	page_size)
+{
+	ulint	offset;
+#ifdef UNIV_DEBUG
+	ulint	left_size;
+#endif
+
+	offset = XDES_ARR_OFFSET + XDES_SIZE * xdes_arr_size(page_size);
+#ifdef UNIV_DEBUG
+	left_size = page_size.physical() - FSP_HEADER_OFFSET - offset
+		- FIL_PAGE_DATA_END;
+
+	ut_ad(left_size >= ENCRYPTION_INFO_SIZE_V2);
+#endif
+
+	return offset;
+}
+
+#if 0 /* MySQL 5.7 Encryption */
+/** Fill the encryption info.
+ at param[in]	space		tablespace
+ at param[in,out]	encrypt_info	buffer for encrypt key.
+ at return true if success. */
+bool
+fsp_header_fill_encryption_info(
+	fil_space_t*		space,
+	byte*			encrypt_info)
+{
+	byte*			ptr;
+	lint			elen;
+	ulint			master_key_id;
+	byte*			master_key;
+	byte			key_info[ENCRYPTION_KEY_LEN * 2];
+	ulint			crc;
+	Encryption::Version	version;
+#ifdef	UNIV_ENCRYPT_DEBUG
+	const byte*		data;
+	ulint			i;
+#endif
+
+	/* Get master key from key ring */
+	Encryption::get_master_key(&master_key_id, &master_key, &version);
+	if (master_key == NULL) {
+		return(false);
+	}
+
+	memset(encrypt_info, 0, ENCRYPTION_INFO_SIZE_V2);
+	memset(key_info, 0, ENCRYPTION_KEY_LEN * 2);
+
+	/* Use the new master key to encrypt the tablespace
+	key. */
+	ut_ad(encrypt_info != NULL);
+	ptr = encrypt_info;
+
+	/* Write magic header. */
+	if (version == Encryption::ENCRYPTION_VERSION_1) {
+		memcpy(ptr, ENCRYPTION_KEY_MAGIC_V1, ENCRYPTION_MAGIC_SIZE);
+	} else {
+		memcpy(ptr, ENCRYPTION_KEY_MAGIC_V2, ENCRYPTION_MAGIC_SIZE);
+	}
+	ptr += ENCRYPTION_MAGIC_SIZE;
+
+	/* Write master key id. */
+	mach_write_to_4(ptr, master_key_id);
+	ptr += sizeof(ulint);
+
+	/* Write server uuid. */
+	if (version == Encryption::ENCRYPTION_VERSION_2) {
+		memcpy(ptr, Encryption::uuid, ENCRYPTION_SERVER_UUID_LEN);
+		ptr += ENCRYPTION_SERVER_UUID_LEN;
+	}
+
+	/* Write tablespace key to temp space. */
+	memcpy(key_info,
+	       space->encryption_key,
+	       ENCRYPTION_KEY_LEN);
+
+	/* Write tablespace iv to temp space. */
+	memcpy(key_info + ENCRYPTION_KEY_LEN,
+	       space->encryption_iv,
+	       ENCRYPTION_KEY_LEN);
+
+#ifdef	UNIV_ENCRYPT_DEBUG
+	fprintf(stderr, "Set %lu:%lu ",space->id,
+		Encryption::master_key_id);
+	for (data = (const byte*) master_key, i = 0;
+	     i < ENCRYPTION_KEY_LEN; i++)
+		fprintf(stderr, "%02lx", (ulong)*data++);
+	fprintf(stderr, " ");
+	for (data = (const byte*) space->encryption_key,
+	     i = 0; i < ENCRYPTION_KEY_LEN; i++)
+		fprintf(stderr, "%02lx", (ulong)*data++);
+	fprintf(stderr, " ");
+	for (data = (const byte*) space->encryption_iv,
+	     i = 0; i < ENCRYPTION_KEY_LEN; i++)
+		fprintf(stderr, "%02lx", (ulong)*data++);
+	fprintf(stderr, "\n");
+#endif
+	/* Encrypt tablespace key and iv. */
+	elen = my_aes_encrypt(
+		key_info,
+		ENCRYPTION_KEY_LEN * 2,
+		ptr,
+		master_key,
+		ENCRYPTION_KEY_LEN,
+		my_aes_256_ecb,
+		NULL, false);
+
+	if (elen == MY_AES_BAD_DATA) {
+		my_free(master_key);
+		return(false);
+	}
+
+	ptr += ENCRYPTION_KEY_LEN * 2;
+
+	/* Write checksum bytes. */
+	crc = ut_crc32(key_info, ENCRYPTION_KEY_LEN * 2);
+	mach_write_to_4(ptr, crc);
+
+	my_free(master_key);
+	return(true);
+}
+#endif /* ! */
+
+/** Rotate the encryption info in the space header.
+ at param[in]	space		tablespace
+ at param[in]      encrypt_info	buffer for re-encrypt key.
+ at param[in,out]	mtr		mini-transaction
+ at return true if success. */
+bool
+fsp_header_rotate_encryption(
+	fil_space_t*		space,
+	byte*			encrypt_info,
+	mtr_t*			mtr)
+{
+	buf_block_t*	block;
+	ulint		offset;
+
+	ut_ad(mtr);
+
+	const page_size_t	page_size(space->flags);
+
+#if MYSQL_ENCRYPTION
+	page_t*		page;
+	ulint		master_key_id;
+	ut_ad(space->encryption_type != Encryption::NONE);
+	/* Fill encryption info. */
+	if (!fsp_header_fill_encryption_info(space,
+					     encrypt_info)) {
+		return(false);
+	}
+#endif
+
+	/* Save the encryption info to the page 0. */
+	block = buf_page_get(page_id_t(space->id, 0),
+			     page_size,
+			     RW_SX_LATCH, mtr);
+	buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
+	ut_ad(space->id == page_get_space_id(buf_block_get_frame(block)));
+
+	offset = fsp_header_get_encryption_offset(page_size);
+	ut_ad(offset != 0 && offset < UNIV_PAGE_SIZE);
+
+
+#if MYSQL_ENCRYPTION
+	page = buf_block_get_frame(block);
+	/* If is in recovering, skip all master key id is rotated
+	tablespaces. */
+	master_key_id = mach_read_from_4(
+		page + offset + ENCRYPTION_MAGIC_SIZE);
+	if (recv_recovery_is_on()
+	    && master_key_id == Encryption::master_key_id) {
+		ut_ad(memcmp(page + offset,
+			     ENCRYPTION_KEY_MAGIC_V1,
+			     ENCRYPTION_MAGIC_SIZE) == 0
+		      || memcmp(page + offset,
+				ENCRYPTION_KEY_MAGIC_V2,
+				ENCRYPTION_MAGIC_SIZE) == 0);
+		return(true);
+	}
+
+	mlog_write_string(page + offset,
+			  encrypt_info,
+			  ENCRYPTION_INFO_SIZE_V2,
+			  mtr);
+#endif /* MYSQL_ENCRYPTION */
+
+	return(true);
+}
+
 /** Initializes the space header of a new created space and creates also the
 insert buffer tree root if space == 0.
 @param[in]	space_id	space id
@@ -944,8 +1161,33 @@ fsp_header_init(
 	fsp_fill_free_list(!is_system_tablespace(space_id),
 			   space, header, mtr);
 
+#if 0 /* MySQL 5.7 Encryption */
+	/* For encryption tablespace, we need to save the encryption
+	info to the page 0. */
+	if (FSP_FLAGS_GET_ENCRYPTION(space->flags)) {
+		ulint	offset = fsp_header_get_encryption_offset(page_size);
+		byte	encryption_info[ENCRYPTION_INFO_SIZE_V2];
+
+		if (offset == 0)
+			return(false);
+
+		if (!fsp_header_fill_encryption_info(space,
+						     encryption_info)) {
+			space->encryption_type = Encryption::NONE;
+			memset(space->encryption_key, 0, ENCRYPTION_KEY_LEN);
+			memset(space->encryption_iv, 0, ENCRYPTION_KEY_LEN);
+			return(false);
+		}
+
+		mlog_write_string(page + offset,
+				  encryption_info,
+				  ENCRYPTION_INFO_SIZE_V2,
+				  mtr);
+	}
+#endif /* ! */
+
 	if (space_id == srv_sys_space.space_id()) {
-		if (btr_create(DICT_CLUSTERED | DICT_IBUF,
+		if (btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
 			       0, univ_page_size, DICT_IBUF_ID_MIN + space_id,
 			       dict_ind_redundant, NULL, mtr) == FIL_NULL) {
 			return(false);
@@ -997,6 +1239,164 @@ fsp_header_get_page_size(
 	return(page_size_t(fsp_header_get_flags(page)));
 }
 
+#if 0 /* MySQL 5.7 Encryption */
+/** Decoding the encryption info
+from the first page of a tablespace.
+ at param[in/out]	key		key
+ at param[in/out]	iv		iv
+ at param[in]	encryption_info	encrytion info.
+ at return true if success */
+bool
+fsp_header_decode_encryption_info(
+	byte*		key,
+	byte*		iv,
+	byte*		encryption_info)
+{
+	byte*			ptr;
+	ulint			master_key_id;
+	byte*			master_key = NULL;
+	lint			elen;
+	byte			key_info[ENCRYPTION_KEY_LEN * 2];
+	ulint			crc1;
+	ulint			crc2;
+	char			srv_uuid[ENCRYPTION_SERVER_UUID_LEN + 1];
+	Encryption::Version	version;
+#ifdef	UNIV_ENCRYPT_DEBUG
+	const byte*		data;
+	ulint			i;
+#endif
+
+	ptr = encryption_info;
+
+	/* For compatibility with 5.7.11, we need to handle the
+	encryption information which created in this old version. */
+	if (memcmp(ptr, ENCRYPTION_KEY_MAGIC_V1,
+		     ENCRYPTION_MAGIC_SIZE) == 0) {
+		version = Encryption::ENCRYPTION_VERSION_1;
+	} else {
+		version = Encryption::ENCRYPTION_VERSION_2;
+	}
+	/* Check magic. */
+	if (version == Encryption::ENCRYPTION_VERSION_2
+	    && memcmp(ptr, ENCRYPTION_KEY_MAGIC_V2, ENCRYPTION_MAGIC_SIZE) != 0) {
+		/* We ignore report error for recovery,
+		since the encryption info maybe hasn't writen
+		into datafile when the table is newly created. */
+		if (!recv_recovery_is_on()) {
+			return(false);
+		} else {
+			return(true);
+		}
+	}
+	ptr += ENCRYPTION_MAGIC_SIZE;
+
+	/* Get master key id. */
+	master_key_id = mach_read_from_4(ptr);
+	ptr += sizeof(ulint);
+
+	/* Get server uuid. */
+	if (version == Encryption::ENCRYPTION_VERSION_2) {
+		memset(srv_uuid, 0, ENCRYPTION_SERVER_UUID_LEN + 1);
+		memcpy(srv_uuid, ptr, ENCRYPTION_SERVER_UUID_LEN);
+		ptr += ENCRYPTION_SERVER_UUID_LEN;
+	}
+
+	/* Get master key by key id. */
+	memset(key_info, 0, ENCRYPTION_KEY_LEN * 2);
+	if (version == Encryption::ENCRYPTION_VERSION_1) {
+		Encryption::get_master_key(master_key_id, NULL, &master_key);
+	} else {
+		Encryption::get_master_key(master_key_id, srv_uuid, &master_key);
+	}
+        if (master_key == NULL) {
+                return(false);
+        }
+
+#ifdef	UNIV_ENCRYPT_DEBUG
+	fprintf(stderr, "%lu ", master_key_id);
+	for (data = (const byte*) master_key, i = 0;
+	     i < ENCRYPTION_KEY_LEN; i++)
+		fprintf(stderr, "%02lx", (ulong)*data++);
+#endif
+
+	/* Decrypt tablespace key and iv. */
+	elen = my_aes_decrypt(
+		ptr,
+		ENCRYPTION_KEY_LEN * 2,
+		key_info,
+		master_key,
+		ENCRYPTION_KEY_LEN,
+		my_aes_256_ecb, NULL, false);
+
+	if (elen == MY_AES_BAD_DATA) {
+		my_free(master_key);
+		return(NULL);
+	}
+
+	/* Check checksum bytes. */
+	ptr += ENCRYPTION_KEY_LEN * 2;
+
+	crc1 = mach_read_from_4(ptr);
+	crc2 = ut_crc32(key_info, ENCRYPTION_KEY_LEN * 2);
+	if (crc1 != crc2) {
+		ib::error() << "Failed to decrpt encryption information,"
+			<< " please check key file is not changed!";
+		return(false);
+	}
+
+	/* Get tablespace key */
+	memcpy(key, key_info, ENCRYPTION_KEY_LEN);
+
+	/* Get tablespace iv */
+	memcpy(iv, key_info + ENCRYPTION_KEY_LEN,
+	       ENCRYPTION_KEY_LEN);
+
+#ifdef	UNIV_ENCRYPT_DEBUG
+	fprintf(stderr, " ");
+	for (data = (const byte*) key,
+	     i = 0; i < ENCRYPTION_KEY_LEN; i++)
+		fprintf(stderr, "%02lx", (ulong)*data++);
+	fprintf(stderr, " ");
+	for (data = (const byte*) iv,
+	     i = 0; i < ENCRYPTION_KEY_LEN; i++)
+		fprintf(stderr, "%02lx", (ulong)*data++);
+	fprintf(stderr, "\n");
+#endif
+
+	my_free(master_key);
+
+	if (Encryption::master_key_id < master_key_id) {
+		Encryption::master_key_id = master_key_id;
+		memcpy(Encryption::uuid, srv_uuid, ENCRYPTION_SERVER_UUID_LEN);
+	}
+
+	return(true);
+}
+
+/** Reads the encryption key from the first page of a tablespace.
+ at param[in]	fsp_flags	tablespace flags
+ at param[in/out]	key		tablespace key
+ at param[in/out]	iv		tablespace iv
+ at param[in]	page	first page of a tablespace
+ at return true if success */
+bool
+fsp_header_get_encryption_key(
+	ulint		fsp_flags,
+	byte*		key,
+	byte*		iv,
+	page_t*		page)
+{
+	ulint			offset;
+	const page_size_t	page_size(fsp_flags);
+	offset = fsp_header_get_encryption_offset(page_size);
+	if (offset == 0) {
+		return(false);
+	}
+
+	return(fsp_header_decode_encryption_info(key, iv, page + offset));
+}
+#endif /* ! */
+
 #ifndef UNIV_HOTBACKUP
 /**********************************************************************//**
 Increases the space size field of a space. */
@@ -1065,7 +1465,7 @@ data file.
 @param[in,out]	header	tablespace header
 @param[in,out]	mtr	mini-transaction
 @return true if success */
-static UNIV_COLD __attribute__((warn_unused_result))
+static UNIV_COLD MY_ATTRIBUTE((warn_unused_result))
 bool
 fsp_try_extend_data_file_with_pages(
 	fil_space_t*	space,
@@ -1097,6 +1497,7 @@ fsp_try_extend_data_file_with_pages(
 @param[in,out]	header	tablespace header
 @param[in,out]	mtr	mini-transaction
 @return whether the tablespace was extended */
+static UNIV_COLD MY_ATTRIBUTE((nonnull))
 ulint
 fsp_try_extend_data_file(
 	fil_space_t*	space,
@@ -1577,7 +1978,7 @@ initialized (may be the same as mtr)
 @retval block	rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
 (init_mtr == mtr, or the page was not previously freed in mtr)
 @retval block	(not allocated or initialized) otherwise */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
 buf_block_t*
 fsp_alloc_free_page(
 	ulint			space,
@@ -1971,7 +2372,6 @@ fsp_alloc_seg_inode(
 	    && !fsp_alloc_seg_inode_page(space_header, mtr)) {
 		return(NULL);
 	}
-
 	const page_size_t	page_size(
 		mach_read_from_4(FSP_SPACE_FLAGS + space_header));
 
@@ -2926,24 +3326,27 @@ fseg_alloc_free_page_general(
 	return(block);
 }
 
-/** Check that we have at least 2 frag pages free in the first extent of a
-single-table tablespace, and they are also physically initialized to the data
-file. That is we have already extended the data file so that those pages are
-inside the data file. If not, this function extends the tablespace with
-pages.
+/** Check that we have at least n_pages frag pages free in the first extent
+of a single-table tablespace, and they are also physically initialized to
+the data file. That is we have already extended the data file so that those
+pages are inside the data file. If not, this function extends the tablespace
+with pages.
 @param[in,out]	space		tablespace
 @param[in,out]	space_header	tablespace header, x-latched
 @param[in]	size		size of the tablespace in pages,
-must be less than FSP_EXTENT_SIZE/2
+must be less than FSP_EXTENT_SIZE
 @param[in,out]	mtr		mini-transaction
- at return true if there were at least 3 free pages, or we were able to extend */
+ at param[in]	n_pages		number of pages to reserve
+ at return true if there were at least n_pages free pages, or we were able
+to extend */
 static
 bool
 fsp_reserve_free_pages(
 	fil_space_t*	space,
 	fsp_header_t*	space_header,
 	ulint		size,
-	mtr_t*		mtr)
+	mtr_t*		mtr,
+	ulint		n_pages)
 {
 	xdes_t*	descr;
 	ulint	n_used;
@@ -2957,13 +3360,12 @@ fsp_reserve_free_pages(
 
 	ut_a(n_used <= size);
 
-	return(size >= n_used + 2
+	return(size >= n_used + n_pages
 	       || fsp_try_extend_data_file_with_pages(
-		       space, n_used + 1, space_header, mtr));
+		       space, n_used + n_pages - 1, space_header, mtr));
 }
 
-/**********************************************************************//**
-Reserves free pages from a tablespace. All mini-transactions which may
+/** Reserves free pages from a tablespace. All mini-transactions which may
 use several pages from the tablespace should call this function beforehand
 and reserve enough free extents so that they certainly will be able
 to do their operation, like a B-tree page split, fully. Reservations
@@ -2982,23 +3384,33 @@ The purpose is to avoid dead end where the database is full but the
 user cannot free any space because these freeing operations temporarily
 reserve some space.
 
-Single-table tablespaces whose size is < 32 pages are a special case. In this
-function we would liberally reserve several 64 page extents for every page
-split or merge in a B-tree. But we do not want to waste disk space if the table
-only occupies < 32 pages. That is why we apply different rules in that special
-case, just ensuring that there are 3 free pages available.
- at return TRUE if we were able to make the reservation */
+Single-table tablespaces whose size is < FSP_EXTENT_SIZE pages are a special
+case. In this function we would liberally reserve several extents for
+every page split or merge in a B-tree. But we do not want to waste disk space
+if the table only occupies < FSP_EXTENT_SIZE pages. That is why we apply
+different rules in that special case, just ensuring that there are n_pages
+free pages available.
+
+ at param[out]	n_reserved	number of extents actually reserved; if we
+				return true and the tablespace size is <
+				FSP_EXTENT_SIZE pages, then this can be 0,
+				otherwise it is n_ext
+ at param[in]	space_id	tablespace identifier
+ at param[in]	n_ext		number of extents to reserve
+ at param[in]	alloc_type	page reservation type (FSP_BLOB, etc)
+ at param[in,out]	mtr		the mini transaction
+ at param[in]	n_pages		for small tablespaces (tablespace size is
+				less than FSP_EXTENT_SIZE), number of free
+				pages to reserve.
+ at return true if we were able to make the reservation */
 bool
 fsp_reserve_free_extents(
-/*=====================*/
-	ulint*	n_reserved,/*!< out: number of extents actually reserved; if we
-			return TRUE and the tablespace size is < 64 pages,
-			then this can be 0, otherwise it is n_ext */
-	ulint	space_id,/*!< in: space id */
-	ulint	n_ext,	/*!< in: number of extents to reserve */
+	ulint*		n_reserved,
+	ulint		space_id,
+	ulint		n_ext,
 	fsp_reserve_t	alloc_type,
-			/*!< in: page reservation type */
-	mtr_t*	mtr)	/*!< in/out: mini-transaction */
+	mtr_t*		mtr,
+	ulint		n_pages)
 {
 	fsp_header_t*	space_header;
 	ulint		n_free_list_ext;
@@ -3009,7 +3421,7 @@ fsp_reserve_free_extents(
 	ulint		reserve= 0;
 	size_t		total_reserved = 0;
 	ulint		rounds = 0;
-	ulint		n_pages_added;
+	ulint		n_pages_added = 0;
 
 	ut_ad(mtr);
 	*n_reserved = n_ext;
@@ -3022,10 +3434,11 @@ fsp_reserve_free_extents(
 	size = mach_read_from_4(space_header + FSP_SIZE);
 	ut_ad(size == space->size_in_header);
 
-	if (alloc_type != FSP_BLOB && size < FSP_EXTENT_SIZE) {
+	if (size < FSP_EXTENT_SIZE && n_pages < 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));
+		return(fsp_reserve_free_pages(space, space_header, size,
+					      mtr, n_pages));
 	}
 
 	n_free_list_ext = flst_get_len(space_header + FSP_FREE);
@@ -3105,7 +3518,6 @@ fsp_reserve_free_extents(
 				   << " rounds: " << rounds
 				   << " total_reserved: " << total_reserved << ".";
 		}
-
 		goto try_again;
 	}
 
@@ -3420,33 +3832,8 @@ fseg_page_is_free(
 }
 
 /**********************************************************************//**
-Checks if a single page is free.
- at return	true if free */
-UNIV_INTERN
-bool
-fsp_page_is_free_func(
-/*==============*/
-	ulint		space_id,	/*!< in: space id */
-	ulint		page_no,	/*!< in: page offset */
-	mtr_t*		mtr,		/*!< in/out: mini-transaction */
-	const char *file,
-	ulint line)
-{
-	ut_ad(mtr);
-
-	const fil_space_t*	space = mtr_x_lock_space(space_id, mtr);
-	const page_size_t	page_size(space->flags);
-
-	xdes_t* descr = xdes_get_descriptor(space_id, page_no, page_size, mtr);
-	ut_a(descr);
-
-	return xdes_mtr_get_bit(
-		descr, XDES_FREE_BIT, page_no % FSP_EXTENT_SIZE, mtr);
-}
-
-/**********************************************************************//**
 Frees an extent of a segment to the space free list. */
-static __attribute__((nonnull))
+static MY_ATTRIBUTE((nonnull))
 void
 fseg_free_extent(
 /*=============*/
@@ -3929,7 +4316,6 @@ fseg_header::to_stream(std::ostream&	out) const
 {
 	const ulint	space = mtr_read_ulint(m_header + FSEG_HDR_SPACE,
 					       MLOG_4BYTES, m_mtr);
-
 	const ulint	page_no = mtr_read_ulint(m_header + FSEG_HDR_PAGE_NO,
 						 MLOG_4BYTES, m_mtr);
 
@@ -3944,6 +4330,31 @@ fseg_header::to_stream(std::ostream&	out) const
 #endif /* UNIV_DEBUG */
 
 /**********************************************************************//**
+Checks if a single page is free.
+ at return	true if free */
+UNIV_INTERN
+bool
+fsp_page_is_free_func(
+/*==============*/
+	ulint		space_id,	/*!< in: space id */
+	ulint		page_no,	/*!< in: page offset */
+	mtr_t*		mtr,		/*!< in/out: mini-transaction */
+	const char *file,
+	ulint line)
+{
+	ut_ad(mtr);
+
+	const fil_space_t*	space = mtr_x_lock_space(space_id, mtr);
+	const page_size_t	page_size(space->flags);
+
+	xdes_t* descr = xdes_get_descriptor(space_id, page_no, page_size, mtr);
+	ut_a(descr);
+
+	return xdes_mtr_get_bit(
+		descr, XDES_FREE_BIT, page_no % FSP_EXTENT_SIZE, mtr);
+}
+
+/**********************************************************************//**
 Compute offset after xdes where crypt data can be stored
 @return	offset */
 ulint
diff --git a/storage/innobase/fsp/fsp0space.cc b/storage/innobase/fsp/fsp0space.cc
index 6f1ef8c..f66f7b8 100644
--- a/storage/innobase/fsp/fsp0space.cc
+++ b/storage/innobase/fsp/fsp0space.cc
@@ -27,8 +27,10 @@ Created 2012-11-16 by Sunny Bains as srv/srv0space.cc
 
 #include "fsp0space.h"
 #include "fsp0sysspace.h"
+#ifndef UNIV_HOTBACKUP
 #include "fsp0fsp.h"
 #include "os0file.h"
+#endif /* !UNIV_HOTBACKUP */
 
 #include "my_sys.h"
 
@@ -70,34 +72,6 @@ Tablespace::shutdown()
 	m_space_id = ULINT_UNDEFINED;
 }
 
-/** Get the sum of the file sizes of each Datafile in a tablespace
- at return ULINT_UNDEFINED if the size is invalid else the sum of sizes */
-ulint
-Tablespace::get_sum_of_sizes() const
-{
-	ulint	sum = 0;
-
-	files_t::const_iterator	end = m_files.end();
-
-	for (files_t::const_iterator it = m_files.begin(); it != end; ++it) {
-
-#ifndef _WIN32
-		if (sizeof(off_t) < 5
-		    && it->m_size >= (1UL << (32UL - UNIV_PAGE_SIZE_SHIFT))) {
-
-			ib::error() << "File size must be < 4 GB with this"
-				" MySQL binary-operating system combination."
-				" In some OS's < 2 GB";
-
-			return(ULINT_UNDEFINED);
-		}
-#endif /* _WIN32 */
-		sum += it->m_size;
-	}
-
-	return(sum);
-}
-
 /** Note that the data file was found.
 @param[in,out] file	Data file object to set */
 void
diff --git a/storage/innobase/fsp/fsp0sysspace.cc b/storage/innobase/fsp/fsp0sysspace.cc
index b1d3ab9..66b5da1 100644
--- a/storage/innobase/fsp/fsp0sysspace.cc
+++ b/storage/innobase/fsp/fsp0sysspace.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, 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
@@ -357,8 +357,14 @@ SysTablespace::check_size(
 	os_offset_t	size = os_file_get_size(file.m_handle);
 	ut_a(size != (os_offset_t) -1);
 
-	/* Round size downward to megabytes */
-	ulint	rounded_size_pages = (ulint) (size >> UNIV_PAGE_SIZE_SHIFT);
+	/* Under some error conditions like disk full scenarios
+	or file size reaching filesystem limit the data file
+	could contain an incomplete extent at the end. When we
+	extend a data file and if some failure happens, then
+	also the data file could contain an incomplete extent.
+	So we need to round the size downward to a  megabyte.*/
+
+	ulint	rounded_size_pages = get_pages_from_size(size);
 
 	/* If last file */
 	if (&file == &m_files.back() && m_auto_extend_last_file) {
@@ -531,6 +537,7 @@ SysTablespace::open_file(
 	return(err);
 }
 
+#ifndef UNIV_HOTBACKUP
 /** Check the tablespace header for this tablespace.
 @param[out]	flushed_lsn	the value of FIL_PAGE_FILE_FLUSH_LSN
 @return DB_SUCCESS or error code */
@@ -574,7 +581,7 @@ SysTablespace::read_lsn_and_check_flags(lsn_t* flushed_lsn)
 	first datafile. */
 	for (int retry = 0; retry < 2; ++retry) {
 
-		err = it->validate_first_page(flushed_lsn);
+		err = it->validate_first_page(flushed_lsn, false);
 
 		if (err != DB_SUCCESS
 		    && (retry == 1
@@ -605,7 +612,7 @@ SysTablespace::read_lsn_and_check_flags(lsn_t* flushed_lsn)
 
 	return(DB_SUCCESS);
 }
-
+#endif /* !UNIV_HOTBACKUP */
 /** Check if a file can be opened in the correct mode.
 @param[in]	file	data file object
 @param[out]	reason	exact reason if file_status check failed.
@@ -752,7 +759,7 @@ SysTablespace::file_found(
 	/* Need to create the system tablespace for new raw device. */
 	return(file.m_type == SRV_NEW_RAW);
 }
-
+#ifndef UNIV_HOTBACKUP
 /** Check the data file specification.
 @param[out] create_new_db	true if a new database is to be created
 @param[in] min_expected_size	Minimum expected tablespace size in bytes
@@ -772,11 +779,7 @@ SysTablespace::check_file_spec(
 		return(DB_ERROR);
 	}
 
-	ulint tablespace_size = get_sum_of_sizes();
-	if (tablespace_size == ULINT_UNDEFINED) {
-		return(DB_ERROR);
-	} else if (tablespace_size
-		   < min_expected_size / UNIV_PAGE_SIZE) {
+	if (get_sum_of_sizes() < min_expected_size / UNIV_PAGE_SIZE) {
 
 		ib::error() << "Tablespace size must be at least "
 			<< min_expected_size / (1024 * 1024) << " MB";
@@ -987,7 +990,7 @@ SysTablespace::open_or_create(
 
 	return(err);
 }
-
+#endif /* UNIV_HOTBACKUP */
 /** Normalize the file size, convert from megabytes to number of pages. */
 void
 SysTablespace::normalize()
diff --git a/storage/innobase/fts/fts0ast.cc b/storage/innobase/fts/fts0ast.cc
index 14e52a9..8c542aa 100644
--- a/storage/innobase/fts/fts0ast.cc
+++ b/storage/innobase/fts/fts0ast.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2007, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2007, 2016, 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
@@ -161,7 +161,7 @@ fts_ast_create_node_term_for_parser(
 
 	/* '%' as first char is forbidden for LIKE in internal SQL parser;
 	'%' as last char is reserved for wildcard search;*/
-	if (len == 0 || len > fts_max_token_size
+	if (len == 0 || len > FTS_MAX_WORD_LEN
 	    || ptr[0] == '%' || ptr[len - 1] == '%') {
 		return(NULL);
 	}
@@ -537,6 +537,36 @@ fts_ast_node_print(
 	fts_ast_node_print_recursive(node, 0);
 }
 
+/** Check only union operation involved in the node
+ at param[in]	node	ast node to check
+ at return true if the node contains only union else false. */
+bool
+fts_ast_node_check_union(
+	fts_ast_node_t*	node)
+{
+	if (node->type == FTS_AST_LIST
+	    || node->type == FTS_AST_SUBEXP_LIST
+	    || node->type == FTS_AST_PARSER_PHRASE_LIST) {
+
+		for (node = node->list.head; node; node = node->next) {
+			if (!fts_ast_node_check_union(node)) {
+				return(false);
+			}
+		}
+
+	} else if (node->type == FTS_AST_OPER
+		   && (node->oper == FTS_IGNORE
+		       || node->oper == FTS_EXIST)) {
+
+		return(false);
+	} else if (node->type == FTS_AST_TEXT) {
+		/* Distance or phrase search query. */
+		return(false);
+	}
+
+	return(true);
+}
+
 /******************************************************************//**
 Traverse the AST - in-order traversal, except for the FTX_EXIST and FTS_IGNORE
 nodes, which will be ignored in the first pass of each level, and visited in a
diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc
index 5edee71..5faa68b 100644
--- a/storage/innobase/fts/fts0fts.cc
+++ b/storage/innobase/fts/fts0fts.cc
@@ -208,19 +208,20 @@ struct fts_tokenize_param_t {
 	ulint		add_pos;	/*!< Added position for tokens */
 };
 
-/****************************************************************//**
-Run SYNC on the table, i.e., write out data from the cache to the
+/** Run SYNC on the table, i.e., write out data from the cache to the
 FTS auxiliary INDEX table and clear the cache at the end.
 @param[in,out]	sync		sync state
 @param[in]	unlock_cache	whether unlock cache lock when write node
 @param[in]	wait		whether wait when a sync is in progress
+ at param[in]      has_dict        whether has dict operation lock
 @return DB_SUCCESS if all OK */
 static
 dberr_t
 fts_sync(
 	fts_sync_t*	sync,
 	bool		unlock_cache,
-	bool		wait);
+	bool		wait,
+	bool		has_dict);
 
 /****************************************************************//**
 Release all resources help by the words rb tree e.g., the node ilist. */
@@ -1979,7 +1980,6 @@ fts_create_common_tables(
 
 func_exit:
 	if (error != DB_SUCCESS) {
-
 		for (it = common_tables.begin(); it != common_tables.end();
 		     ++it) {
 			row_drop_table_for_mysql(
@@ -3648,7 +3648,7 @@ fts_add_doc_by_id(
 
 				DBUG_EXECUTE_IF(
 					"fts_instrument_sync_debug",
-					fts_sync(cache->sync, true, true);
+					fts_sync(cache->sync, true, true, false);
 				);
 
 				DEBUG_SYNC_C("fts_instrument_sync_request");
@@ -3929,6 +3929,8 @@ fts_write_node(
 	doc_id_t	first_doc_id;
 	char		table_name[MAX_FULL_NAME_LEN];
 
+	ut_a(node->ilist != NULL);
+
 	if (*graph) {
 		info = (*graph)->info;
 	} else {
@@ -4446,7 +4448,7 @@ fts_sync_index(
 
 	ut_ad(rbt_validate(index_cache->words));
 
-	error = fts_sync_write_words(sync->trx, index_cache, sync->unlock_cache);
+	error = fts_sync_write_words(trx, index_cache, sync->unlock_cache);
 
 #ifdef FTS_DOC_STATS_DEBUG
 	/* FTS_RESOLVE: the word counter info in auxiliary table "DOC_ID"
@@ -4463,13 +4465,11 @@ fts_sync_index(
 }
 
 /** Check if index cache has been synced completely
- at param[in,out]	sync		sync state
 @param[in,out]	index_cache	index cache
 @return true if index is synced, otherwise false. */
 static
 bool
 fts_sync_index_check(
-	fts_sync_t*		sync,
 	fts_index_cache_t*	index_cache)
 {
 	const ib_rbt_node_t*	rbt_node;
@@ -4492,14 +4492,36 @@ fts_sync_index_check(
 	return(true);
 }
 
-/*********************************************************************//**
-Commit the SYNC, change state of processed doc ids etc.
+/** Reset synced flag in index cache when rollback
+ at param[in,out]	index_cache	index cache */
+static
+void
+fts_sync_index_reset(
+	fts_index_cache_t*	index_cache)
+{
+	const ib_rbt_node_t*	rbt_node;
+
+	for (rbt_node = rbt_first(index_cache->words);
+	     rbt_node != NULL;
+	     rbt_node = rbt_next(index_cache->words, rbt_node)) {
+
+		fts_tokenizer_word_t*	word;
+		word = rbt_value(fts_tokenizer_word_t, rbt_node);
+
+		fts_node_t*	fts_node;
+		fts_node = static_cast<fts_node_t*>(ib_vector_last(word->nodes));
+
+		fts_node->synced = false;
+	}
+}
+
+/** Commit the SYNC, change state of processed doc ids etc.
+ at param[in,out]	sync	sync state
 @return DB_SUCCESS if all OK */
 static  MY_ATTRIBUTE((nonnull, warn_unused_result))
 dberr_t
 fts_sync_commit(
-/*============*/
-	fts_sync_t*	sync)			/*!< in: sync state */
+	fts_sync_t*	sync)
 {
 	dberr_t		error;
 	trx_t*		trx = sync->trx;
@@ -4550,6 +4572,8 @@ fts_sync_commit(
 			<< " ins/sec";
 	}
 
+	/* Avoid assertion in trx_free(). */
+	trx->dict_operation_lock_mode = 0;
 	trx_free_for_background(trx);
 
 	return(error);
@@ -4572,6 +4596,10 @@ fts_sync_rollback(
 		index_cache = static_cast<fts_index_cache_t*>(
 			ib_vector_get(cache->indexes, i));
 
+		/* Reset synced flag so nodes will not be skipped
+		in the next sync, see fts_sync_write_words(). */
+		fts_sync_index_reset(index_cache);
+
 		for (j = 0; fts_index_selector[j].value; ++j) {
 
 			if (index_cache->ins_graph[j] != NULL) {
@@ -4597,6 +4625,9 @@ fts_sync_rollback(
 	rw_lock_x_unlock(&cache->lock);
 
 	fts_sql_rollback(trx);
+
+	/* Avoid assertion in trx_free(). */
+	trx->dict_operation_lock_mode = 0;
 	trx_free_for_background(trx);
 }
 
@@ -4605,13 +4636,15 @@ FTS auxiliary INDEX table and clear the cache at the end.
 @param[in,out]	sync		sync state
 @param[in]	unlock_cache	whether unlock cache lock when write node
 @param[in]	wait		whether wait when a sync is in progress
+ at param[in]      has_dict        whether has dict operation lock
 @return DB_SUCCESS if all OK */
 static
 dberr_t
 fts_sync(
 	fts_sync_t*	sync,
 	bool		unlock_cache,
-	bool		wait)
+	bool		wait,
+	bool		has_dict)
 {
 	ulint		i;
 	dberr_t		error = DB_SUCCESS;
@@ -4640,6 +4673,12 @@ fts_sync(
 	DEBUG_SYNC_C("fts_sync_begin");
 	fts_sync_begin(sync);
 
+	/* When sync in background, we hold dict operation lock
+	to prevent DDL like DROP INDEX, etc. */
+	if (has_dict) {
+		sync->trx->dict_operation_lock_mode = RW_S_LATCH;
+	}
+
 begin_sync:
 	if (cache->total_size > fts_max_cache_size) {
 		/* Avoid the case: sync never finish when
@@ -4676,7 +4715,7 @@ fts_sync(
 			ib_vector_get(cache->indexes, i));
 
 		if (index_cache->index->to_be_dropped
-		    || fts_sync_index_check(sync, index_cache)) {
+		    || fts_sync_index_check(index_cache)) {
 			continue;
 		}
 
@@ -4691,6 +4730,7 @@ fts_sync(
 	}
 
 	rw_lock_x_lock(&cache->lock);
+	sync->interrupted = false;
 	sync->in_progress = false;
 	os_event_set(sync->event);
 	rw_lock_x_unlock(&cache->lock);
@@ -4714,19 +4754,23 @@ FTS auxiliary INDEX table and clear the cache at the end.
 @param[in,out]	table		fts table
 @param[in]	unlock_cache	whether unlock cache when write node
 @param[in]	wait		whether wait for existing sync to finish
+ at param[in]	has_dict	whether has dict operation lock
 @return DB_SUCCESS on success, error code on failure. */
 dberr_t
 fts_sync_table(
 	dict_table_t*	table,
 	bool		unlock_cache,
-	bool		wait)
+	bool		wait,
+	bool		has_dict)
 {
 	dberr_t	err = DB_SUCCESS;
 
 	ut_ad(table->fts);
 
-	if (!dict_table_is_discarded(table) && table->fts->cache) {
-		err = fts_sync(table->fts->cache->sync, unlock_cache, wait);
+	if (!dict_table_is_discarded(table) && table->fts->cache
+	    && !dict_table_is_corrupted(table)) {
+		err = fts_sync(table->fts->cache->sync,
+			       unlock_cache, wait, has_dict);
 	}
 
 	return(err);
@@ -5114,7 +5158,7 @@ fts_tokenize_document(
 	ut_a(doc->charset);
 
 	doc->tokens = rbt_create_arg_cmp(
-                                         sizeof(fts_token_t), innobase_fts_text_cmp, (void*) doc->charset);
+		sizeof(fts_token_t), innobase_fts_text_cmp, (void*) doc->charset);
 
 	if (parser != NULL) {
 		fts_tokenize_param_t	fts_param;
@@ -5809,6 +5853,8 @@ fts_update_doc_id(
 
 	if (error == DB_SUCCESS) {
 		dict_index_t*	clust_index;
+		dict_col_t*	col = dict_table_get_nth_col(
+			table, table->fts->doc_col);
 
 		ufield->exp = NULL;
 
@@ -5816,8 +5862,8 @@ fts_update_doc_id(
 
 		clust_index = dict_table_get_first_index(table);
 
-		ufield->field_no = dict_col_get_clust_pos(
-			&table->cols[table->fts->doc_col], clust_index);
+		ufield->field_no = dict_col_get_clust_pos(col, clust_index);
+		dict_col_copy_type(col, dfield_get_type(&ufield->new_val));
 
 		/* It is possible we update record that has
 		not yet be sync-ed from last crash. */
@@ -6784,11 +6830,7 @@ fts_fake_hex_to_dec(
 #ifdef UNIV_DEBUG
 	ret =
 #endif /* UNIV_DEBUG */
-#ifdef _WIN32
-	sscanf(tmp_id, "%016llu", &dec_id);
-#else
-	sscanf(tmp_id, "%016llu", &dec_id);
-#endif /* _WIN32 */
+	sscanf(tmp_id, "%016" UINT64scan, &dec_id);
 	ut_ad(ret == 1);
 
 	return dec_id;
@@ -7995,10 +8037,9 @@ fts_init_index(
 consistent state. For now consistency is check only by ensuring
 index->page_no != FIL_NULL
 @param[out]	base_table	table has host fts index
- at param[in,out]	trx		trx handler
- at return true if check certifies auxillary tables are sane false otherwise. */
-bool
-fts_is_corrupt(
+ at param[in,out]	trx		trx handler */
+void
+fts_check_corrupt(
 	dict_table_t*	base_table,
 	trx_t*		trx)
 {
@@ -8016,7 +8057,7 @@ fts_is_corrupt(
 		fts_get_table_name(&fts_table, table_name);
 
 		dict_table_t*	aux_table = dict_table_open_on_name(
-			table_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
+			table_name, true, FALSE, DICT_ERR_IGNORE_NONE);
 
 		if (aux_table == NULL) {
 			dict_set_corrupted(
@@ -8045,6 +8086,4 @@ fts_is_corrupt(
 
 		dict_table_close(aux_table, FALSE, FALSE);
 	}
-
-	return(sane);
 }
diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc
index 89cdcf2..5989aff 100644
--- a/storage/innobase/fts/fts0opt.cc
+++ b/storage/innobase/fts/fts0opt.cc
@@ -602,7 +602,7 @@ fts_zip_read_word(
 		/* Finished decompressing block. */
 		if (zip->zp->avail_in == 0) {
 
-			/* Free the block that's been decompressed. */
+			/* Free the block thats been decompressed. */
 			if (zip->pos > 0) {
 				ulint	prev = zip->pos - 1;
 
@@ -1507,6 +1507,12 @@ fts_optimize_write_word(
 		fts_node_t* node = (fts_node_t*) ib_vector_get(nodes, i);
 
 		if (error == DB_SUCCESS) {
+			/* Skip empty node. */
+			if (node->ilist == NULL) {
+				ut_ad(node->ilist_size == 0);
+				continue;
+			}
+
 			error = fts_write_node(
 				trx, &graph, fts_table, word, node);
 
@@ -2635,7 +2641,6 @@ fts_optimize_remove_table(
 
 /** Send sync fts cache for the table.
 @param[in]	table	table to sync */
-UNIV_INTERN
 void
 fts_optimize_request_sync_table(
 	dict_table_t*	table)
@@ -2650,7 +2655,7 @@ fts_optimize_request_sync_table(
 
 	/* FTS optimizer thread is already exited */
 	if (fts_opt_start_shutdown) {
-		ib::info() << "Try to remove table " << table->name
+		ib::info() << "Try to sync table " << table->name
 			<< " after FTS optimize thread exiting.";
 		return;
 	}
@@ -2964,7 +2969,7 @@ fts_optimize_sync_table(
 
 	if (table) {
 		if (dict_table_has_fts_index(table) && table->fts->cache) {
-			fts_sync_table(table, true, false);
+			fts_sync_table(table, true, false, true);
 		}
 
 		dict_table_close(table, FALSE, FALSE);
@@ -3122,26 +3127,7 @@ fts_optimize_thread(
 				ib_vector_get(tables, i));
 
 			if (slot->state != FTS_STATE_EMPTY) {
-				dict_table_t*	table = NULL;
-
-				/*slot->table may be freed, so we try to open
-				table by slot->table_id.*/
-			        table = dict_table_open_on_id(
-					slot->table_id, FALSE,
-					DICT_TABLE_OP_NORMAL);
-
-				if (table) {
-
-					if (dict_table_has_fts_index(table)) {
-						fts_sync_table(table, false, true);
-					}
-
-					if (table->fts) {
-						fts_free(table);
-					}
-
-					dict_table_close(table, FALSE, FALSE);
-				}
+				fts_optimize_sync_table(slot->table_id);
 			}
 		}
 	}
@@ -3155,7 +3141,7 @@ fts_optimize_thread(
 
 	/* We count the number of threads in os_thread_exit(). A created
 	thread should always use that to exit and not use return() to exit. */
-	os_thread_exit(NULL);
+	os_thread_exit();
 
 	OS_THREAD_DUMMY_RETURN;
 }
@@ -3189,11 +3175,9 @@ fts_optimize_is_init(void)
 	return(fts_optimize_wq != NULL);
 }
 
-/**********************************************************************//**
-Signal the optimize thread to prepare for shutdown. */
+/** Shutdown fts optimize thread. */
 void
-fts_optimize_start_shutdown(void)
-/*=============================*/
+fts_optimize_shutdown()
 {
 	ut_ad(!srv_read_only_mode);
 
@@ -3222,17 +3206,5 @@ fts_optimize_start_shutdown(void)
 	os_event_destroy(fts_opt_shutdown_event);
 
 	ib_wqueue_free(fts_optimize_wq);
-}
-
-/**********************************************************************//**
-Reset the work queue. */
-void
-fts_optimize_end(void)
-/*==================*/
-{
-	ut_ad(!srv_read_only_mode);
-
-	// FIXME: Potential race condition here: We should wait for
-	// the optimize thread to confirm shutdown.
 	fts_optimize_wq = NULL;
 }
diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc
index 8abeb63..dee7c59 100644
--- a/storage/innobase/fts/fts0que.cc
+++ b/storage/innobase/fts/fts0que.cc
@@ -153,6 +153,13 @@ struct fts_query_t {
 	bool		multi_exist;	/*!< multiple FTS_EXIST oper */
 
 	st_mysql_ftparser*	parser;	/*!< fts plugin parser */
+
+	/** limit value for the fts query */
+	ulonglong		limit;
+
+	/** number of docs fetched by query. This is to restrict the
+	result with limit value */
+	ulonglong		n_docs;
 };
 
 /** For phrase matching, first we collect the documents and the positions
@@ -2700,7 +2707,7 @@ fts_query_phrase_split(
 /*****************************************************************//**
 Text/Phrase search.
 @return DB_SUCCESS or error code */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
 dberr_t
 fts_query_phrase_search(
 /*====================*/
@@ -3209,6 +3216,11 @@ fts_query_filter_doc_ids(
 	ulint		decoded = 0;
 	ib_rbt_t*	doc_freqs = word_freq->doc_freqs;
 
+	if (query->limit != ULONG_UNDEFINED
+	    && query->n_docs >= query->limit) {
+		return(DB_SUCCESS);
+	}
+
 	/* Decode the ilist and add the doc ids to the query doc_id set. */
 	while (decoded < len) {
 		ulint		freq = 0;
@@ -3296,11 +3308,17 @@ fts_query_filter_doc_ids(
 			/* Add the word to the document's matched RB tree. */
 			fts_query_add_word_to_document(query, doc_id, word);
 		}
+
+		if (query->limit != ULONG_UNDEFINED
+		    && query->limit <= ++query->n_docs) {
+			goto func_exit;
+		}
 	}
 
 	/* Some sanity checks. */
 	ut_a(doc_id == node->last_doc_id);
 
+func_exit:
 	if (query->total_size > fts_result_cache_limit) {
 		return(DB_FTS_EXCEED_RESULT_CACHE_LIMIT);
 	} else {
@@ -3904,19 +3922,24 @@ fts_query_can_optimize(
 	}
 }
 
-/*******************************************************************//**
-FTS Query entry point.
+/** FTS Query entry point.
+ at param[in]	trx		transaction
+ at param[in]	index		fts index to search
+ at param[in]	flags		FTS search mode
+ at param[in]	query_str	FTS query
+ at param[in]	query_len	FTS query string len in bytes
+ at param[in,out]	result		result doc ids
+ at param[in]	limit		limit value
 @return DB_SUCCESS if successful otherwise error code */
 dberr_t
 fts_query(
-/*======*/
-	trx_t*		trx,		/*!< in: transaction */
-	dict_index_t*	index,		/*!< in: The FTS index to search */
-	uint		flags,		/*!< in: FTS search mode */
-	const byte*	query_str,	/*!< in: FTS query */
-	ulint		query_len,	/*!< in: FTS query string len
-					in bytes */
-	fts_result_t**	result)		/*!< in/out: result doc ids */
+	trx_t*		trx,
+	dict_index_t*	index,
+	uint		flags,
+	const byte*	query_str,
+	ulint		query_len,
+	fts_result_t**	result,
+	ulonglong	limit)
 {
 	fts_query_t	query;
 	dberr_t		error = DB_SUCCESS;
@@ -3971,13 +3994,16 @@ fts_query(
 
 	if (flags & FTS_EXPAND) {
 		query.wildcard_words = rbt_create_arg_cmp(
-			sizeof(fts_string_t), innobase_fts_text_cmp, (void*)charset);
+			sizeof(fts_string_t), innobase_fts_text_cmp, (void *)charset);
 	}
 
 	query.total_size += SIZEOF_RBT_CREATE;
 
 	query.total_docs = dict_table_get_n_rows(index->table);
 
+	query.limit = limit;
+
+	query.n_docs = 0;
 #ifdef FTS_DOC_STATS_DEBUG
 	if (ft_enable_diag_print) {
 		error = fts_get_total_word_count(
@@ -4053,6 +4079,19 @@ fts_query(
 			        fts_result_cache_limit = 2048;
 		);
 
+		/* Optimisation is allowed for limit value
+		when
+		i)  No ranking involved
+		ii) Only FTS Union operations involved. */
+		if (query.limit != ULONG_UNDEFINED
+		    && !fts_ast_node_check_union(ast)) {
+			query.limit = ULONG_UNDEFINED;
+		}
+
+		DBUG_EXECUTE_IF("fts_union_limit_off",
+			query.limit = ULONG_UNDEFINED;
+		);
+
 		/* Traverse the Abstract Syntax Tree (AST) and execute
 		the query. */
 		query.error = fts_ast_visit(
diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc
index 45f0bd9..512fce3 100644
--- a/storage/innobase/gis/gis0rtree.cc
+++ b/storage/innobase/gis/gis0rtree.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2016, 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
@@ -152,7 +152,9 @@ rtr_index_build_node_ptr(
 
 	tuple = dtuple_create(heap, n_unique + 1);
 
-	dtuple_set_n_fields_cmp(tuple, n_unique);
+	/* For rtree internal node, we need to compare page number
+	fields. */
+	dtuple_set_n_fields_cmp(tuple, n_unique + 1);
 
 	dict_index_copy_types(tuple, index, n_unique);
 
@@ -621,7 +623,7 @@ rtr_update_mbr_field(
 
 /**************************************************************//**
 Update parent page's MBR and Predicate lock information during a split */
-static __attribute__((nonnull))
+static MY_ATTRIBUTE((nonnull))
 void
 rtr_adjust_upper_level(
 /*===================*/
@@ -723,8 +725,6 @@ rtr_adjust_upper_level(
 		node_ptr_upper, &rec, &dummy_big_rec, 0, NULL, mtr);
 
 	if (err == DB_FAIL) {
-		ut_ad(!cursor.rtr_info);
-
 		cursor.rtr_info = sea_cur->rtr_info;
 		cursor.tree_height = sea_cur->tree_height;
 
@@ -1025,6 +1025,7 @@ rtr_page_split_and_insert(
 	lock_prdt_t		new_prdt;
 	rec_t*			first_rec = NULL;
 	int			first_rec_group = 1;
+	ulint			n_iterations = 0;
 
 	if (!*heap) {
 		*heap = mem_heap_create(1024);
@@ -1229,6 +1230,15 @@ rtr_page_split_and_insert(
 	page_cur_search(insert_block, cursor->index, tuple,
 			PAGE_CUR_LE, page_cursor);
 
+	/* It's possible that the new record is too big to be inserted into
+	the page, and it'll need the second round split in this case.
+	We test this scenario here*/
+	DBUG_EXECUTE_IF("rtr_page_need_second_split",
+			if (n_iterations == 0) {
+				rec = NULL;
+				goto after_insert; }
+	);
+
 	rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
 				    offsets, heap, n_ext, mtr);
 
@@ -1247,6 +1257,9 @@ rtr_page_split_and_insert(
 		again. */
 	}
 
+#ifdef UNIV_DEBUG
+after_insert:
+#endif
 	/* Calculate the mbr on the upper half-page, and the mbr on
 	original page. */
 	rtr_page_cal_mbr(cursor->index, block, &mbr, *heap);
@@ -1279,6 +1292,7 @@ rtr_page_split_and_insert(
 			block, new_block, mtr);
 	}
 
+
 	/* If the new res insert fail, we need to do another split
 	 again. */
 	if (!rec) {
@@ -1289,9 +1303,12 @@ rtr_page_split_and_insert(
 			ibuf_reset_free_bits(block);
 		}
 
-		*offsets = rtr_page_get_father_block(
-                                NULL, *heap, cursor->index, block, mtr,
-				NULL, cursor);
+		/* We need to clean the parent path here and search father
+		node later, otherwise, it's possible that find a wrong
+		parent. */
+		rtr_clean_rtr_info(cursor->rtr_info, true);
+		cursor->rtr_info = NULL;
+		n_iterations++;
 
 		rec_t* i_rec = page_rec_get_next(page_get_infimum_rec(
 			buf_block_get_frame(block)));
@@ -1411,19 +1428,19 @@ rtr_page_copy_rec_list_end_no_locks(
 	page_cur_t	page_cur;
 	page_cur_t	cur1;
 	rec_t*		cur_rec;
-	dtuple_t*	tuple;
-	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
-	ulint*		offsets		= offsets_;
-	ulint		n_fields = 0;
+	ulint		offsets_1[REC_OFFS_NORMAL_SIZE];
+	ulint*		offsets1 = offsets_1;
+	ulint		offsets_2[REC_OFFS_NORMAL_SIZE];
+	ulint*		offsets2 = offsets_2;
 	ulint		moved = 0;
 	bool		is_leaf = page_is_leaf(new_page);
 
-	rec_offs_init(offsets_);
+	rec_offs_init(offsets_1);
+	rec_offs_init(offsets_2);
 
 	page_cur_position(rec, block, &cur1);
 
 	if (page_cur_is_before_first(&cur1)) {
-
 		page_cur_move_to_next(&cur1);
 	}
 
@@ -1436,30 +1453,27 @@ rtr_page_copy_rec_list_end_no_locks(
 		page_get_infimum_rec(buf_block_get_frame(new_block)));
 	page_cur_position(cur_rec, new_block, &page_cur);
 
-	n_fields = dict_index_get_n_fields(index);
-
 	/* Copy records from the original page to the new page */
 	while (!page_cur_is_after_last(&cur1)) {
 		rec_t*	cur1_rec = page_cur_get_rec(&cur1);
 		rec_t*	ins_rec;
 
-		/* Find the place to insert. */
-		tuple = dict_index_build_data_tuple(index, cur1_rec,
-						    n_fields, heap);
-
 		if (page_rec_is_infimum(cur_rec)) {
 			cur_rec = page_rec_get_next(cur_rec);
 		}
 
+		offsets1 = rec_get_offsets(cur1_rec, index, offsets1,
+					   ULINT_UNDEFINED, &heap);
 		while (!page_rec_is_supremum(cur_rec)) {
 			ulint		cur_matched_fields = 0;
 			int		cmp;
 
-			offsets = rec_get_offsets(
-					cur_rec, index, offsets,
-					dtuple_get_n_fields_cmp(tuple), &heap);
-			cmp = cmp_dtuple_rec_with_match(tuple, cur_rec, offsets,
-							&cur_matched_fields);
+			offsets2 = rec_get_offsets(cur_rec, index, offsets2,
+						   ULINT_UNDEFINED, &heap);
+			cmp = cmp_rec_rec_with_match(cur1_rec, cur_rec,
+						     offsets1, offsets2,
+						     index, FALSE,
+						     &cur_matched_fields);
 			if (cmp < 0) {
 				page_cur_move_to_prev(&page_cur);
 				break;
@@ -1490,11 +1504,11 @@ rtr_page_copy_rec_list_end_no_locks(
 
 		cur_rec = page_cur_get_rec(&page_cur);
 
-		offsets = rec_get_offsets(cur1_rec, index, offsets,
-					  ULINT_UNDEFINED, &heap);
+		offsets1 = rec_get_offsets(cur1_rec, index, offsets1,
+					   ULINT_UNDEFINED, &heap);
 
 		ins_rec = page_cur_insert_rec_low(cur_rec, index,
-						  cur1_rec, offsets, mtr);
+						  cur1_rec, offsets1, mtr);
 		if (UNIV_UNLIKELY(!ins_rec)) {
 			fprintf(stderr, "page number %ld and %ld\n",
 				(long)new_block->page.id.page_no(),
@@ -1540,17 +1554,16 @@ rtr_page_copy_rec_list_start_no_locks(
 {
 	page_cur_t	cur1;
 	rec_t*		cur_rec;
-	dtuple_t*	tuple;
-	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
-	ulint*		offsets	= offsets_;
-	ulint		n_fields = 0;
+	ulint		offsets_1[REC_OFFS_NORMAL_SIZE];
+	ulint*		offsets1 = offsets_1;
+	ulint		offsets_2[REC_OFFS_NORMAL_SIZE];
+	ulint*		offsets2 = offsets_2;
 	page_cur_t	page_cur;
 	ulint		moved = 0;
 	bool		is_leaf = page_is_leaf(buf_block_get_frame(block));
 
-	rec_offs_init(offsets_);
-
-	n_fields = dict_index_get_n_fields(index);
+	rec_offs_init(offsets_1);
+	rec_offs_init(offsets_2);
 
 	page_cur_set_before_first(block, &cur1);
 	page_cur_move_to_next(&cur1);
@@ -1563,23 +1576,23 @@ rtr_page_copy_rec_list_start_no_locks(
 		rec_t*	cur1_rec = page_cur_get_rec(&cur1);
 		rec_t*	ins_rec;
 
-		/* Find the place to insert. */
-		tuple = dict_index_build_data_tuple(index, cur1_rec,
-						    n_fields, heap);
-
 		if (page_rec_is_infimum(cur_rec)) {
 			cur_rec = page_rec_get_next(cur_rec);
 		}
 
+		offsets1 = rec_get_offsets(cur1_rec, index, offsets1,
+					   ULINT_UNDEFINED, &heap);
+
 		while (!page_rec_is_supremum(cur_rec)) {
 			ulint		cur_matched_fields = 0;
 			int		cmp;
 
-			offsets = rec_get_offsets(cur_rec, index, offsets,
-						  dtuple_get_n_fields_cmp(tuple),
-						  &heap);
-			cmp = cmp_dtuple_rec_with_match(tuple, cur_rec, offsets,
-							&cur_matched_fields);
+			offsets2 = rec_get_offsets(cur_rec, index, offsets2,
+						   ULINT_UNDEFINED, &heap);
+			cmp = cmp_rec_rec_with_match(cur1_rec, cur_rec,
+						     offsets1, offsets2,
+						     index, FALSE,
+						     &cur_matched_fields);
 			if (cmp < 0) {
 				page_cur_move_to_prev(&page_cur);
 				cur_rec = page_cur_get_rec(&page_cur);
@@ -1612,11 +1625,11 @@ rtr_page_copy_rec_list_start_no_locks(
 
 		cur_rec = page_cur_get_rec(&page_cur);
 
-		offsets = rec_get_offsets(cur1_rec, index, offsets,
-					  ULINT_UNDEFINED, &heap);
+		offsets1 = rec_get_offsets(cur1_rec, index, offsets1,
+					   ULINT_UNDEFINED, &heap);
 
 		ins_rec = page_cur_insert_rec_low(cur_rec, index,
-						  cur1_rec, offsets, mtr);
+						  cur1_rec, offsets1, mtr);
 		if (UNIV_UNLIKELY(!ins_rec)) {
 			fprintf(stderr, "page number %ld and %ld\n",
 				(long)new_block->page.id.page_no(),
@@ -1689,36 +1702,6 @@ rtr_merge_mbr_changed(
 		mbr++;
 	}
 
-	if (!changed) {
-		rec_t*	rec1;
-		rec_t*	rec2;
-		ulint*	offsets1;
-		ulint*	offsets2;
-		mem_heap_t*	heap;
-
-		heap = mem_heap_create(100);
-
-		rec1 = page_rec_get_next(
-			page_get_infimum_rec(
-				buf_block_get_frame(merge_block)));
-
-		offsets1 = rec_get_offsets(
-			rec1, index, NULL, ULINT_UNDEFINED, &heap);
-
-		rec2 = page_rec_get_next(
-			page_get_infimum_rec(
-				buf_block_get_frame(block)));
-		offsets2 = rec_get_offsets(
-			rec2, index, NULL, ULINT_UNDEFINED, &heap);
-
-		/* Check any primary key fields have been changed */
-		if (cmp_rec_rec(rec1, rec2, offsets1, offsets2, index) != 0) {
-			changed = true;
-		}
-
-		mem_heap_free(heap);
-	}
-
 	return(changed);
 }
 
@@ -1887,7 +1870,7 @@ rtr_estimate_n_rows_in_range(
 
 	/* Read mbr from tuple. */
 	const dfield_t*	dtuple_field;
-	ulint		dtuple_f_len __attribute__((unused));
+	ulint		dtuple_f_len MY_ATTRIBUTE((unused));
 	rtr_mbr_t	range_mbr;
 	double		range_area;
 	byte*		range_mbr_ptr;
diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc
index 26440b5..2c0c5b4 100644
--- a/storage/innobase/gis/gis0sea.cc
+++ b/storage/innobase/gis/gis0sea.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2016, 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
@@ -310,7 +310,7 @@ rtr_pcur_getnext_from_path(
 		page_cursor->rec = NULL;
 
 		if (mode == PAGE_CUR_RTREE_LOCATE) {
-			if (level == target_level) {
+			if (level == target_level && level == 0) {
 				ulint	low_match;
 
 				found = false;
@@ -336,10 +336,15 @@ rtr_pcur_getnext_from_path(
 					}
 				}
 			} else {
+				page_cur_mode_t	page_mode = mode;
+
+				if (level == target_level
+				    && target_level != 0) {
+					page_mode = PAGE_CUR_RTREE_GET_FATHER;
+				}
 				found = rtr_cur_search_with_match(
-					block, index, tuple,
-					PAGE_CUR_RTREE_LOCATE, page_cursor,
-					btr_cur->rtr_info);
+					block, index, tuple, page_mode,
+					page_cursor, btr_cur->rtr_info);
 
 				/* Save the position of parent if needed */
 				if (found && need_parent) {
@@ -428,6 +433,9 @@ rtr_pcur_getnext_from_path(
 					page_cur_get_block(page_cursor),
 					r_cur);
 
+				btr_cur->low_match = level != 0 ?
+					DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1
+					: btr_cur->low_match;
 				break;
 			}
 
@@ -641,6 +649,41 @@ rtr_pcur_open_low(
 	}
 }
 
+/* Get the rtree page father.
+ at param[in]	index		rtree index
+ at param[in]	block		child page in the index
+ at param[in]	mtr		mtr
+ at param[in]	sea_cur		search cursor, contains information
+				about parent nodes in search
+ at param[in]	cursor		cursor on node pointer record,
+				its page x-latched */
+void
+rtr_page_get_father(
+	dict_index_t*	index,
+	buf_block_t*	block,
+	mtr_t*		mtr,
+	btr_cur_t*	sea_cur,
+	btr_cur_t*	cursor)
+{
+	mem_heap_t*	heap = mem_heap_create(100);
+#ifdef UNIV_DEBUG
+	ulint*		offsets;
+
+	offsets = rtr_page_get_father_block(
+		NULL, heap, index, block, mtr, sea_cur, cursor);
+
+	ulint	page_no = btr_node_ptr_get_child_page_no(cursor->page_cur.rec,
+							 offsets);
+
+	ut_ad(page_no == block->page.id.page_no());
+#else
+	rtr_page_get_father_block(
+		NULL, heap, index, block, mtr, sea_cur, cursor);
+#endif
+
+	mem_heap_free(heap);
+}
+
 /************************************************************//**
 Returns the father block to a page. It is assumed that mtr holds
 an X or SX latch on the tree.
@@ -658,6 +701,7 @@ rtr_page_get_father_block(
 	btr_cur_t*	cursor)	/*!< out: cursor on node pointer record,
 				its page x-latched */
 {
+
 	rec_t*  rec = page_rec_get_next(
 		page_get_infimum_rec(buf_block_get_frame(block)));
 	btr_cur_position(index, rec, block, cursor);
@@ -785,14 +829,13 @@ rtr_get_father_node(
 	ulint		n_fields;
 	bool		new_rtr = false;
 
-get_parent:
 	/* Try to optimally locate the parent node. Level should always
 	less than sea_cur->tree_height unless the root is splitting */
 	if (sea_cur && sea_cur->tree_height > level) {
 
 		ut_ad(mtr_memo_contains_flagged(mtr,
 						dict_index_get_lock(index),
- 						MTR_MEMO_X_LOCK
+						MTR_MEMO_X_LOCK
 						| MTR_MEMO_SX_LOCK));
 		ret = rtr_cur_restore_position(
 			BTR_CONT_MODIFY_TREE, sea_cur, level, mtr);
@@ -812,6 +855,8 @@ rtr_get_father_node(
 			page_cur_position(rec,
 					  btr_pcur_get_block(r_cursor),
 					  btr_cur_get_page_cur(btr_cur));
+			btr_cur->rtr_info = sea_cur->rtr_info;
+			btr_cur->tree_height = sea_cur->tree_height;
 			ut_ad(rtr_compare_cursor_rec(
 				index, btr_cur, page_no, &heap));
 			goto func_exit;
@@ -838,14 +883,13 @@ rtr_get_father_node(
 			BTR_CONT_MODIFY_TREE, btr_cur, 0,
 			__FILE__, __LINE__, mtr);
 
-
 	} else {
 		/* btr_validate */
 		ut_ad(level >= 1);
 		ut_ad(!sea_cur);
 
 		btr_cur_search_to_nth_level(
-			index, level - 1, tuple, PAGE_CUR_RTREE_LOCATE,
+			index, level, tuple, PAGE_CUR_RTREE_LOCATE,
 			BTR_CONT_MODIFY_TREE, btr_cur, 0,
 			__FILE__, __LINE__, mtr);
 
@@ -856,50 +900,11 @@ rtr_get_father_node(
 		    || (btr_cur->low_match != n_fields)) {
 			ret = rtr_pcur_getnext_from_path(
 				tuple, PAGE_CUR_RTREE_LOCATE, btr_cur,
-				level - 1, BTR_CONT_MODIFY_TREE,
+				level, BTR_CONT_MODIFY_TREE,
 				true, mtr);
 
 			ut_ad(ret && btr_cur->low_match == n_fields);
 		}
-
-		/* Since there could be some identical recs in different
-		pages, we still need to compare the page_no field to
-		verify we have the right parent. */
-		btr_pcur_t*	r_cursor = rtr_get_parent_cursor(btr_cur,
-								 level,
-								 false);
-		rec = btr_pcur_get_rec(r_cursor);
-
-		ulint* offsets = rec_get_offsets(rec, index, NULL,
-						 ULINT_UNDEFINED, &heap);
-		while (page_no != btr_node_ptr_get_child_page_no(rec, offsets)) {
-			ret = rtr_pcur_getnext_from_path(
-				tuple, PAGE_CUR_RTREE_LOCATE, btr_cur,
-				level - 1, BTR_CONT_MODIFY_TREE,
-				true, mtr);
-
-			ut_ad(ret && btr_cur->low_match == n_fields);
-
-			/* There must be a rec in the path, if the path
-			is run out, the spatial index is corrupted. */
-			if (!ret) {
-				mutex_enter(&dict_sys->mutex);
-				dict_set_corrupted_index_cache_only(index);
-				mutex_exit(&dict_sys->mutex);
-
-				ib::info() << "InnoDB: Corruption of a"
-					" spatial index " << index->name
-					<< " of table " << index->table->name;
-				break;
-			}
-			r_cursor = rtr_get_parent_cursor(btr_cur, level, false);
-			rec = btr_pcur_get_rec(r_cursor);
-			offsets = rec_get_offsets(rec, index, NULL,
-						  ULINT_UNDEFINED, &heap);
-		}
-
-		sea_cur = btr_cur;
-		goto get_parent;
 	}
 
 	ret = rtr_compare_cursor_rec(
@@ -1249,8 +1254,8 @@ rtr_check_discard_page(
 	mutex_exit(&index->rtr_track->rtr_active_mutex);
 
 	lock_mutex_enter();
-	lock_prdt_free_from_discard_page(block, lock_sys->prdt_hash);
-	lock_prdt_free_from_discard_page(block, lock_sys->prdt_page_hash);
+	lock_prdt_page_free_from_discard(block, lock_sys->prdt_hash);
+	lock_prdt_page_free_from_discard(block, lock_sys->prdt_page_hash);
 	lock_mutex_exit();
 }
 
@@ -1784,6 +1789,10 @@ rtr_cur_search_with_match(
 					}
 				}
 				break;
+			case PAGE_CUR_RTREE_GET_FATHER:
+				cmp = cmp_dtuple_rec_with_gis_internal(
+					tuple, rec, offsets);
+				break;
 			default:
 				/* WITHIN etc. */
 				cmp = cmp_dtuple_rec_with_gis(
@@ -1807,6 +1816,12 @@ rtr_cur_search_with_match(
 				if (!is_leaf) {
 					ulint		page_no;
 					node_seq_t	new_seq;
+					bool		is_loc;
+
+					is_loc = (orig_mode
+						  == PAGE_CUR_RTREE_LOCATE
+						  || orig_mode
+						  == PAGE_CUR_RTREE_GET_FATHER);
 
 					offsets = rec_get_offsets(
 						rec, index, offsets,
@@ -1827,8 +1842,7 @@ rtr_cur_search_with_match(
 						new_seq, level - 1, 0,
 						NULL, 0);
 
-					if (orig_mode
-					    == PAGE_CUR_RTREE_LOCATE) {
+					if (is_loc) {
 						rtr_non_leaf_insert_stack_push(
 							index,
 							rtr_info->parent_path,
@@ -1838,8 +1852,7 @@ rtr_cur_search_with_match(
 
 					if (!srv_read_only_mode
 					    && (rtr_info->need_page_lock
-						|| orig_mode
-						!= PAGE_CUR_RTREE_LOCATE)) {
+						|| !is_loc)) {
 
 						/* Lock the page, preventing it
 						from being shrunk */
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index e12cc31..e1e4262 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -50,6 +50,8 @@ this program; if not, write to the Free Software Foundation, Inc.,
 #include <sql_show.h>
 #include <sql_table.h>
 #include <sql_tablespace.h>
+// MySQL 5.7 Header */
+// #include <sql_thd_internal_api.h>
 #include <table_cache.h>
 #include <my_check_opt.h>
 #include <my_bitmap.h>
@@ -123,8 +125,10 @@ this program; if not, write to the Free Software Foundation, Inc.,
 
 #define thd_get_trx_isolation(X) ((enum_tx_isolation)thd_tx_isolation(X))
 
+extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all);
+
 #ifdef MYSQL_DYNAMIC_PLUGIN
-#define tc_size 2000
+#define tc_size  400
 #define tdc_size 400
 #endif
 
@@ -137,14 +141,13 @@ this program; if not, write to the Free Software Foundation, Inc.,
 
 /* for ha_innopart, Native InnoDB Partitioning. */
 /* JAN: TODO: MySQL 5.7 Native InnoDB Partitioning */
-//#include "ha_innopart.h"
+#ifdef HAVE_HA_INNOPART_H
+#include "ha_innopart.h"
+#endif
+
 #include <mysql/plugin.h>
 #include <mysql/service_wsrep.h>
 
-# ifndef MYSQL_PLUGIN_IMPORT
-#  define MYSQL_PLUGIN_IMPORT /* nothing */
-# endif /* MYSQL_PLUGIN_IMPORT */
-
 #ifdef WITH_WSREP
 #include "dict0priv.h"
 #include "../storage/innobase/include/ut0byte.h"
@@ -172,27 +175,6 @@ static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid);
 static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
 #endif /* WITH_WSREP */
 
-static
-void
-innobase_set_cursor_view(
-/*=====================*/
-	handlerton*	hton,	/*!< in: innobase hton */
-	THD*		thd,	/*!< in: user thread handle */
-	void*		curview);/*!< in: Consistent cursor view to be set */
-static
-void*
-innobase_create_cursor_view(
-/*========================*/
-	handlerton*	hton,	/*!< in: innobase hton */
-	THD*		thd);	/*!< in: user thread handle */
-static
-void
-innobase_close_cursor_view(
-/*=======================*/
-	handlerton*	hton,	/*!< in: innobase hton */
-	THD*		thd,	/*!< in: user thread handle */
-	void*		curview);/*!< in: Consistent read view to be closed */
-
 /** to protect innobase_open_files */
 static mysql_mutex_t innobase_share_mutex;
 /** to force correct commit order in binlog */
@@ -213,7 +195,7 @@ static const long AUTOINC_NEW_STYLE_LOCKING = 1;
 static const long AUTOINC_NO_LOCKING = 2;
 
 static long innobase_log_buffer_size;
-static long innobase_open_files;
+static long innobase_open_files=0;
 static long innobase_autoinc_lock_mode;
 static ulong innobase_commit_concurrency = 0;
 static ulong innobase_read_io_threads;
@@ -292,7 +274,8 @@ enum default_row_format_enum {
 	DEFAULT_ROW_FORMAT_COMPACT = 1,
 	DEFAULT_ROW_FORMAT_DYNAMIC = 2,
 };
-/* JAN: TODO: MySQL 5.7 */
+
+static
 void set_my_errno(int err)
 {
 	errno = err;
@@ -492,6 +475,7 @@ static PSI_mutex_info all_innodb_mutexes[] = {
 	PSI_KEY(ibuf_mutex),
 	PSI_KEY(ibuf_pessimistic_insert_mutex),
 	PSI_KEY(log_sys_mutex),
+	PSI_KEY(log_sys_write_mutex),
 	PSI_KEY(mutex_list_mutex),
 	PSI_KEY(page_zip_stat_per_index_mutex),
 	PSI_KEY(purge_sys_pq_mutex),
@@ -529,6 +513,7 @@ static PSI_mutex_info all_innodb_mutexes[] = {
 	PSI_KEY(rtr_ssn_mutex),
 	PSI_KEY(trx_sys_mutex),
 	PSI_KEY(zip_pad_mutex),
+	PSI_KEY(master_key_id_mutex),
 };
 # endif /* UNIV_PFS_MUTEX */
 
@@ -554,10 +539,7 @@ static PSI_rwlock_info all_innodb_rwlocks[] = {
 	PSI_RWLOCK_KEY(index_tree_rw_lock),
 	PSI_RWLOCK_KEY(index_online_log),
 	PSI_RWLOCK_KEY(dict_table_stats),
-	PSI_RWLOCK_KEY(hash_table_locks),
-#  ifdef UNIV_DEBUG
-	PSI_RWLOCK_KEY(buf_chunk_map_latch)
-#  endif /* UNIV_DEBUG */
+	PSI_RWLOCK_KEY(hash_table_locks)
 };
 # endif /* UNIV_PFS_RWLOCK */
 
@@ -580,6 +562,7 @@ static PSI_thread_info	all_innodb_threads[] = {
 	PSI_KEY(srv_master_thread),
 	PSI_KEY(srv_monitor_thread),
 	PSI_KEY(srv_purge_thread),
+	PSI_KEY(srv_worker_thread),
 	PSI_KEY(trx_rollback_clean_thread),
 };
 # endif /* UNIV_PFS_THREAD */
@@ -645,70 +628,42 @@ ib_cb_t innodb_api_cb[] = {
 	(ib_cb_t) ib_cfg_bk_commit_interval,
 	(ib_cb_t) ib_ut_strerr,
 	(ib_cb_t) ib_cursor_stmt_begin,
-	(ib_cb_t) ib_trx_read_only
+	(ib_cb_t) ib_trx_read_only,
+	(ib_cb_t) ib_is_virtual_table
 };
 
-/**
-  Test a file path whether it is same as mysql data directory path.
-
-  @param path null terminated character string
-
-  @return
-    @retval TRUE The path is different from mysql data directory.
-    @retval FALSE The path is same as mysql data directory.
-*/
-static bool is_mysql_datadir_path(const char *path)
+/******************************************************************//**
+Function used to loop a thread (for debugging/instrumentation
+purpose). */
+void
+srv_debug_loop(void)
+/*================*/
 {
-  if (path == NULL)
-    return false;
-
-  char mysql_data_dir[FN_REFLEN], path_dir[FN_REFLEN];
-  convert_dirname(path_dir, path, NullS);
-  convert_dirname(mysql_data_dir, mysql_unpacked_real_data_home, NullS);
-  size_t mysql_data_home_len= dirname_length(mysql_data_dir);
-  size_t path_len = dirname_length(path_dir);
-
-  if (path_len < mysql_data_home_len)
-    return true;
-
-  if (!lower_case_file_system)
-    return(memcmp(mysql_data_dir, path_dir, mysql_data_home_len));
-
-  return(files_charset_info->coll->strnncoll(files_charset_info,
-                                            (uchar *) path_dir, path_len,
-                                            (uchar *) mysql_data_dir,
-                                            mysql_data_home_len,
-                                            TRUE));
+        ibool set = TRUE;
 
+        while (set) {
+                os_thread_yield();
+        }
 }
 
+/******************************************************************//**
+Debug function used to read a MBR data */
 
-static int mysql_tmpfile_path(const char *path, const char *prefix)
+#ifdef UNIV_DEBUG
+void
+srv_mbr_debug(const byte* data)
 {
-  DBUG_ASSERT(path != NULL);
-  DBUG_ASSERT((strlen(path) + strlen(prefix)) <= FN_REFLEN);
-
-  char filename[FN_REFLEN];
-  File fd = create_temp_file(filename, path, prefix,
-#ifdef __WIN__
-                             O_BINARY | O_TRUNC | O_SEQUENTIAL |
-                             O_SHORT_LIVED |
-#endif /* __WIN__ */
-                             O_CREAT | O_EXCL | O_RDWR | O_TEMPORARY,
-                             MYF(MY_WME));
-  if (fd >= 0) {
-#ifndef __WIN__
-    /*
-      This can be removed once the following bug is fixed:
-      Bug #28903  create_temp_file() doesn't honor O_TEMPORARY option
-                  (file not removed) (Unix)
-    */
-    unlink(filename);
-#endif /* !__WIN__ */
-  }
-
-  return fd;
+	double a, b, c , d;
+	a = mach_double_read(data);
+	data += sizeof(double);
+	b = mach_double_read(data);
+	data += sizeof(double);
+	c = mach_double_read(data);
+	data += sizeof(double);
+	d = mach_double_read(data);
+	ut_ad(a && b && c &&d);
 }
+#endif
 
 static void innodb_remember_check_sysvar_funcs();
 mysql_var_check_func check_sysvar_enum;
@@ -744,37 +699,6 @@ ha_create_table_option innodb_table_option_list[]=
   HA_TOPTION_END
 };
 
-/******************************************************************//**
-Function used to loop a thread (for debugging/instrumentation
-purpose). */
-void
-srv_debug_loop(void)
-/*================*/
-{
-        ibool set = TRUE;
-
-        while (set) {
-                os_thread_yield();
-        }
-}
-
-/******************************************************************//**
-Debug function used to read a MBR data */
-#ifdef UNIV_DEBUG
-void
-srv_mbr_debug(const byte* data)
-{
-	double a, b, c , d;
-        a = mach_double_read(data);
-        data += sizeof(double);
-        b = mach_double_read(data);
-        data += sizeof(double);
-        c = mach_double_read(data);
-        data += sizeof(double);
-        d = mach_double_read(data);
-	ut_ad(a && b && c &&d);
-}
-#endif
 /*************************************************************//**
 Check whether valid argument given to innodb_ft_*_stopword_table.
 This function is registered as a callback with MySQL.
@@ -790,6 +714,8 @@ innodb_stopword_table_validate(
 						for update function */
 	struct st_mysql_value*		value);	/*!< in: incoming string */
 
+static bool is_mysql_datadir_path(const char *path);
+
 /** Validate passed-in "value" is a valid directory name.
 This function is registered as a callback with MySQL.
 @param[in,out]	thd	thread handle
@@ -840,6 +766,7 @@ innodb_tmpdir_validate(
 		return(1);
 	}
 
+	os_normalize_path(alter_tmp_dir);
 	my_realpath(tmp_abs_path, alter_tmp_dir, 0);
 	size_t	tmp_abs_len = strlen(tmp_abs_path);
 
@@ -910,6 +837,7 @@ uint
 get_field_offset(
 	const TABLE*	table,
 	const Field*	field);
+
 /*************************************************************//**
 Check for a valid value of innobase_compression_algorithm.
 @return	0 for valid innodb_compression_algorithm. */
@@ -943,9 +871,41 @@ innodb_encrypt_tables_validate(
 
 static const char innobase_hton_name[]= "InnoDB";
 
+static const char*	deprecated_innodb_support_xa
+	= "Using innodb_support_xa is deprecated and the"
+	" parameter may be removed in future releases.";
+
+static const char*	deprecated_innodb_support_xa_off
+	= "Using innodb_support_xa is deprecated and the"
+	" parameter may be removed in future releases."
+	" Only innodb_support_xa=ON is allowed.";
+
+/** Update the session variable innodb_support_xa.
+ at param[in]	thd	current session
+ at param[in]	var	the system variable innodb_support_xa
+ at param[in,out]	var_ptr	the contents of the variable
+ at param[in]	save	the to-be-updated value */
+static
+void
+innodb_support_xa_update(
+	THD*				thd,
+	struct st_mysql_sys_var*	var,
+	void*				var_ptr,
+	const void*			save)
+{
+	my_bool	innodb_support_xa = *static_cast<const my_bool*>(save);
+
+	push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+		     HA_ERR_WRONG_COMMAND,
+		     innodb_support_xa
+		     ? deprecated_innodb_support_xa
+		     : deprecated_innodb_support_xa_off);
+}
+
 static MYSQL_THDVAR_BOOL(support_xa, PLUGIN_VAR_OPCMDARG,
   "Enable InnoDB support for the XA two-phase commit",
-  NULL, NULL, TRUE);
+  /* check_func */ NULL, innodb_support_xa_update,
+  /* default */ TRUE);
 
 static MYSQL_THDVAR_BOOL(table_locks, PLUGIN_VAR_OPCMDARG,
   "Enable InnoDB locking in LOCK TABLES",
@@ -970,9 +930,6 @@ static MYSQL_THDVAR_STR(ft_user_stopword_table,
   "User supplied stopword table name, effective in the session level.",
   innodb_stopword_table_validate, NULL, NULL);
 
-/* JAN: TODO: MySQL 5.7 */
-#define SHOW_SCOPE_GLOBAL 0
-
 static MYSQL_THDVAR_STR(tmpdir,
   PLUGIN_VAR_OPCMDARG|PLUGIN_VAR_MEMALLOC,
   "Directory for temporary non-tablespace files.",
@@ -1101,6 +1058,7 @@ static SHOW_VAR innodb_status_variables[]= {
   {"ahi_drop_lookups",
   (char*) &export_vars.innodb_ahi_drop_lookups,           SHOW_LONG},
 #endif /* UNIV_DEBUG */
+
   /* Status variables for page compression */
   {"page_compression_saved",
    (char*) &export_vars.innodb_page_compression_saved,    SHOW_LONGLONG},
@@ -1206,6 +1164,7 @@ static SHOW_VAR innodb_status_variables[]= {
   {"scrub_background_page_split_failures_unknown",
    (char*) &export_vars.innodb_scrub_page_split_failures_unknown,
    SHOW_LONG},
+
   {NullS, NullS, SHOW_LONG}
 };
 
@@ -1237,6 +1196,7 @@ innobase_close_connection(
 	THD*		thd);		/*!< in: MySQL thread handle for
 					which to close the connection */
 
+#ifdef MYSQL_KILL_CONNECTION
 /*****************************************************************//**
 Cancel any pending lock request associated with the current THD. */
 static
@@ -1246,6 +1206,7 @@ innobase_kill_connection(
 	handlerton*	hton,		/*!< in/out: InnoDB handlerton */
 	THD*		thd);		/*!< in: MySQL thread handle for
 					which to close the connection */
+#endif /* MYSQL_KILL_CONNECTION */
 
 static void innobase_kill_query(handlerton *hton, THD* thd, enum thd_kill_levels level);
 static void innobase_commit_ordered(handlerton *hton, THD* thd, bool all);
@@ -1438,6 +1399,7 @@ innobase_rollback_by_xid(
 	XID*		xid);		/*!< in: X/Open XA transaction
 					identification */
 
+#ifdef MYSQL_TABLESPACES
 /** This API handles CREATE, ALTER & DROP commands for InnoDB tablespaces.
 @param[in]	hton		Handlerton of InnoDB
 @param[in]	thd		Connection
@@ -1449,6 +1411,7 @@ innobase_alter_tablespace(
 	handlerton*		hton,
 	THD*			thd,
 	st_alter_tablespace*	alter_info);
+#endif /* MYSQL_TABLESPACES */
 
 /** Remove all tables in the named database inside InnoDB.
 @param[in]	hton	handlerton from InnoDB
@@ -1484,6 +1447,7 @@ innobase_start_trx_and_assign_read_view(
 	THD*		thd);		/* in: MySQL thread handle of the
 					user for whom the transaction should
 					be committed */
+
 /** Flush InnoDB redo logs to the file system.
 @param[in]	hton			InnoDB handlerton
 @param[in]	binlog_group_flush	true if we got invoked by binlog
@@ -1492,17 +1456,35 @@ group commit during flush stage, false in other cases.
 static
 bool
 innobase_flush_logs(
-	handlerton*	hton,		/*!< in: InnoDB handlerton */
-	bool binlog_group_flush);
-/** Flush InnoDB redo logs to the file system.
- at param[in]	hton			InnoDB handlerton
- at param[in]	binlog_group_flush	true if we got invoked by binlog
-group commit during flush stage, false in other cases.
- at return false */
-static
-bool
-innobase_flush_logs(
-	handlerton*	hton);		/*!< in: InnoDB handlerton */
+	handlerton*	hton,
+	bool		binlog_group_flush)
+{
+	DBUG_ENTER("innobase_flush_logs");
+	DBUG_ASSERT(hton == innodb_hton_ptr);
+
+	if (srv_read_only_mode) {
+		DBUG_RETURN(false);
+	}
+
+	/* If !binlog_group_flush, we got invoked by FLUSH LOGS or similar.
+	Else, we got invoked by binlog group commit during flush stage. */
+
+	if (binlog_group_flush && srv_flush_log_at_trx_commit == 0) {
+		/* innodb_flush_log_at_trx_commit=0
+		(write and sync once per second).
+		Do not flush the redo log during binlog group commit. */
+		DBUG_RETURN(false);
+	}
+
+	/* Flush the redo log buffer to the redo log file.
+	Sync it to disc if we are in FLUSH LOGS, or if
+	innodb_flush_log_at_trx_commit=1
+	(write and sync at each commit). */
+	log_buffer_flush_to_disk(!binlog_group_flush
+				 || srv_flush_log_at_trx_commit == 1);
+
+	DBUG_RETURN(false);
+}
 
 /** Flush InnoDB redo logs to the file system.
 @param[in]	hton			InnoDB handlerton
@@ -1578,6 +1560,7 @@ innobase_fill_i_s_table(
 	return(ret);
 }
 
+#ifdef MYSQL_STORE_FTS_DOC_ID
 /** Store doc_id value into FTS_DOC_ID field
 @param[in,out]	tbl	table containing FULLTEXT index
 @param[in]	doc_id	FTS_DOC_ID value */
@@ -1590,11 +1573,11 @@ innobase_fts_store_docid(
 	my_bitmap_map*	old_map
 		= dbug_tmp_use_all_columns(tbl, tbl->write_set);
 
-	/* JAN: TODO: MySQL 5.7 */
-	//tbl->fts_doc_id_field->store(static_cast<longlong>(doc_id), true);
+	tbl->fts_doc_id_field->store(static_cast<longlong>(doc_id), true);
 
 	dbug_tmp_restore_column_map(tbl->write_set, old_map);
 }
+#endif
 
 /*************************************************************//**
 Check for a valid value of innobase_commit_concurrency.
@@ -1638,6 +1621,7 @@ innobase_create_handler(
 	TABLE_SHARE*	table,
 	MEM_ROOT*	mem_root)
 {
+#ifdef MYSQL_INNODB_PARTITIONS
 	/* If the table:
 	1) have type InnoDB (not the generic partition handlerton)
 	2) have partitioning defined
@@ -1647,16 +1631,15 @@ innobase_create_handler(
 	    && table->db_type() == innodb_hton_ptr // 1)
 	    && table->partition_info_str           // 2)
 	    && table->partition_info_str_len) {    // 2)
-		/* JAN: TODO: MySQL 5.7 InnoDB Partitioning disabled
 		ha_innopart* file = new (mem_root) ha_innopart(hton, table);
 		if (file && file->init_partitioning(mem_root))
 		{
 			delete file;
 			return(NULL);
 		}
-		return(file);*/
-		return (NULL);
+		return(file);
 	}
+#endif
 
 	return(new (mem_root) ha_innobase(hton, table));
 }
@@ -1950,19 +1933,6 @@ thd_is_select(
 }
 
 /******************************************************************//**
-Returns true if the thread supports XA,
-global value of innodb_supports_xa if thd is NULL.
- at return true if thd has XA support */
-ibool
-thd_supports_xa(
-/*============*/
-	THD*	thd)	/*!< in: thread handle, or NULL to query
-			the global innodb_supports_xa */
-{
-	return(THDVAR(thd, support_xa));
-}
-
-/******************************************************************//**
 Returns the lock wait timeout for the current connection.
 @return the lock wait timeout, in seconds */
 ulong
@@ -1989,10 +1959,34 @@ thd_set_lock_wait_time(
 	}
 }
 
+/** Get the value of innodb_tmpdir.
+ at param[in]	thd	thread handle, or NULL to query
+			the global innodb_tmpdir.
+ at retval NULL if innodb_tmpdir="" */
+const char*
+thd_innodb_tmpdir(
+	THD*	thd)
+{
+
+#ifdef UNIV_DEBUG
+	trx_t*	trx = thd_to_trx(thd);
+	btrsea_sync_check	check(trx->has_search_latch);
+	ut_ad(!sync_check_iterate(check));
+#endif /* UNIV_DEBUG */
+
+	const char*	tmp_dir = THDVAR(thd, tmpdir);
+
+	if (tmp_dir != NULL && *tmp_dir == '\0') {
+		tmp_dir = NULL;
+	}
+
+	return(tmp_dir);
+}
+
 /** Obtain the private handler of InnoDB session specific data.
 @param[in,out]	thd	MySQL thread handler.
 @return reference to private handler */
-__attribute__((warn_unused_result))
+MY_ATTRIBUTE((warn_unused_result))
 static
 innodb_session_t*&
 thd_to_innodb_session(
@@ -2015,7 +2009,7 @@ thd_to_innodb_session(
 /** Obtain the InnoDB transaction of a MySQL thread.
 @param[in,out]	thd	MySQL thread handler.
 @return reference to transaction pointer */
-MY_ATTRIBUTE((warn_unused_result, nonnull))
+MY_ATTRIBUTE((warn_unused_result))
 trx_t*&
 thd_to_trx(
 	THD*	thd)
@@ -2026,6 +2020,19 @@ thd_to_trx(
 	return(innodb_session->m_trx);
 }
 
+#ifdef WITH_WSREP
+/********************************************************************//**
+Obtain the InnoDB transaction id of a MySQL thread.
+ at return	transaction id */
+__attribute__((warn_unused_result, nonnull))
+ulonglong
+thd_to_trx_id(
+	THD*	thd)	/*!< in: MySQL thread */
+{
+	return(thd_to_trx(thd)->id);
+}
+#endif /* WITH_WSREP */
+
 /** Check if statement is of type INSERT .... SELECT that involves
 use of intrinsic tables.
 @param[in]	thd	thread handler
@@ -2067,20 +2074,6 @@ add_table_to_thread_cache(
 	priv->register_table_handler(table->name.m_name, table);
 }
 
-#ifdef WITH_WSREP
-/********************************************************************//**
-Obtain the InnoDB transaction id of a MySQL thread.
- at return	transaction id */
-__attribute__((warn_unused_result, nonnull))
-ulonglong
-thd_to_trx_id(
-/*=======*/
-	THD*	thd)	/*!< in: MySQL thread */
-{
-	return(thd_to_trx(thd)->id);
-}
-#endif /* WITH_WSREP */
-
 /********************************************************************//**
 Call this function when mysqld passes control to the client. That is to
 avoid deadlocks on the adaptive hash S-latch possibly held by thd. For more
@@ -2158,11 +2151,9 @@ convert_error_code_to_mysql(
 				    "depth of %d. Please "
 				    "drop extra constraints and try "
 				    "again", DICT_FK_MAX_RECURSIVE_LOAD);
-		return(-1);; /* unspecified error */
-		/* JAN: TODO: MySQL 5.7
+
 		my_error(ER_FK_DEPTH_EXCEEDED, MYF(0), FK_MAX_CASCADE_DEL);
 		return(HA_ERR_FK_DEPTH_EXCEEDED);
-		*/
 
 	case DB_CANT_CREATE_GEOMETRY_OBJECT:
 		my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, MYF(0));
@@ -2212,7 +2203,7 @@ convert_error_code_to_mysql(
 
 		if (thd) {
 			thd_mark_transaction_to_rollback(
-				thd, (int) row_rollback_on_timeout);
+				thd, (bool) row_rollback_on_timeout);
 		}
 
 		return(HA_ERR_LOCK_WAIT_TIMEOUT);
@@ -2223,6 +2214,7 @@ convert_error_code_to_mysql(
 	case DB_ROW_IS_REFERENCED:
 		return(HA_ERR_ROW_IS_REFERENCED);
 
+	case DB_NO_FK_ON_S_BASE_COL:
 	case DB_CANNOT_ADD_CONSTRAINT:
 	case DB_CHILD_NO_INDEX:
 	case DB_PARENT_NO_INDEX:
@@ -2260,10 +2252,7 @@ convert_error_code_to_mysql(
 		return(HA_ERR_DECRYPTION_FAILED);
 
 	case DB_TABLESPACE_NOT_FOUND:
-		/* JAN: TODO: MySQL 5.7
 		return(HA_ERR_TABLESPACE_MISSING);
-		*/
-		return(HA_ERR_NO_SUCH_TABLE);
 
 	case DB_TOO_BIG_RECORD: {
 		/* If prefix is true then a 768-byte prefix is stored
@@ -2325,29 +2314,17 @@ convert_error_code_to_mysql(
 	case DB_TABLESPACE_EXISTS:
 		return(HA_ERR_TABLESPACE_EXISTS);
 	case DB_TABLESPACE_DELETED:
-		/* JAN: TODO: MySQL 5.7
 		return(HA_ERR_TABLESPACE_MISSING);
-		*/
-		return(HA_ERR_NO_SUCH_TABLE);
 	case DB_IDENTIFIER_TOO_LONG:
 		return(HA_ERR_INTERNAL_ERROR);
 	case DB_TABLE_CORRUPT:
-		/* JAN: TODO: MySQL 5.7
 		return(HA_ERR_TABLE_CORRUPT);
-		*/
-		return(HA_ERR_INTERNAL_ERROR);
 	case DB_FTS_TOO_MANY_WORDS_IN_PHRASE:
 		return(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE);
 	case DB_WRONG_FILE_NAME:
-		/* JAN: TODO: MySQL 5.7
 		return(HA_ERR_WRONG_FILE_NAME);
-		*/
-		return(HA_ERR_INTERNAL_ERROR);
 	case DB_COMPUTE_VALUE_FAILED:
-		/* JAN: TODO: MySQL 5.7
 		return(HA_ERR_COMPUTE_FAILED);
-		*/
-		return(HA_ERR_INTERNAL_ERROR);
 	}
 }
 
@@ -2549,7 +2526,7 @@ Thread unsafe, can only be called from the thread owning the THD.
 @return			SQL statement string */
 const char*
 innobase_get_stmt_unsafe(
-/*==============*/
+/*=====================*/
 	THD*	thd,
 	size_t*	length)
 {
@@ -2557,6 +2534,8 @@ innobase_get_stmt_unsafe(
 	const char* query=NULL;
 
 	stmt = thd_query_string(thd);
+	// MySQL 5.7
+	//stmt = thd_query_unsafe(thd);
 
 	if (stmt && stmt->str) {
 		*length = stmt->length;
@@ -2577,7 +2556,7 @@ into the provided buffer.
 @return			Length of the SQL statement */
 size_t
 innobase_get_stmt_safe(
-/*==============*/
+/*===================*/
 	THD*	thd,
 	char*	buf,
 	size_t	buflen)
@@ -2625,12 +2604,73 @@ innobase_get_lower_case_table_names(void)
 	return(lower_case_table_names);
 }
 
-/*********************************************************************//**
-Creates a temporary file.
+/**
+  Test a file path whether it is same as mysql data directory path.
+
+  @param path null terminated character string
+
+  @return
+    @retval TRUE The path is different from mysql data directory.
+    @retval FALSE The path is same as mysql data directory.
+*/
+static bool is_mysql_datadir_path(const char *path)
+{
+  if (path == NULL)
+    return false;
+
+  char mysql_data_dir[FN_REFLEN], path_dir[FN_REFLEN];
+  convert_dirname(path_dir, path, NullS);
+  convert_dirname(mysql_data_dir, mysql_unpacked_real_data_home, NullS);
+  size_t mysql_data_home_len= dirname_length(mysql_data_dir);
+  size_t path_len = dirname_length(path_dir);
+
+  if (path_len < mysql_data_home_len)
+    return true;
+
+  if (!lower_case_file_system)
+    return(memcmp(mysql_data_dir, path_dir, mysql_data_home_len));
+
+  return(files_charset_info->coll->strnncoll(files_charset_info,
+                                            (uchar *) path_dir, path_len,
+                                            (uchar *) mysql_data_dir,
+                                            mysql_data_home_len,
+                                            TRUE));
+}
+
+static int mysql_tmpfile_path(const char *path, const char *prefix)
+{
+  DBUG_ASSERT(path != NULL);
+  DBUG_ASSERT((strlen(path) + strlen(prefix)) <= FN_REFLEN);
+
+  char filename[FN_REFLEN];
+  File fd = create_temp_file(filename, path, prefix,
+#ifdef __WIN__
+                             O_BINARY | O_TRUNC | O_SEQUENTIAL |
+                             O_SHORT_LIVED |
+#endif /* __WIN__ */
+                             O_CREAT | O_EXCL | O_RDWR | O_TEMPORARY,
+                             MYF(MY_WME));
+  if (fd >= 0) {
+#ifndef __WIN__
+    /*
+      This can be removed once the following bug is fixed:
+      Bug #28903  create_temp_file() doesn't honor O_TEMPORARY option
+                  (file not removed) (Unix)
+    */
+    unlink(filename);
+#endif /* !__WIN__ */
+  }
+
+  return fd;
+}
+
+/** Creates a temporary file in the location specified by the parameter
+path. If the path is NULL, then it will be created in tmpdir.
+ at param[in]	path	location for creating temporary file
 @return temporary file descriptor, or < 0 on error */
 int
-innobase_mysql_tmpfile(void)
-/*========================*/
+innobase_mysql_tmpfile(
+	const char*	path)
 {
 #ifdef WITH_INNODB_DISALLOW_WRITES
 	os_event_wait(srv_allow_writes_event);
@@ -2643,7 +2683,11 @@ innobase_mysql_tmpfile(void)
 		return(-1);
 	);
 
-	fd = mysql_tmpfile("ib");
+	if (path == NULL) {
+		fd = mysql_tmpfile("ib");
+	} else {
+		fd = mysql_tmpfile_path(path, "ib");
+	}
 
 	if (fd >= 0) {
 		/* Copy the file descriptor, so that the additional resources
@@ -2683,9 +2727,9 @@ innobase_mysql_tmpfile(void)
 			set_my_errno(errno);
 			my_strerror(errbuf, sizeof(errbuf), my_errno);
 			my_error(EE_OUT_OF_FILERESOURCES,
-				 MYF(ME_BELL+ME_WAITTANG),
-				"ib*", my_errno,
-				errbuf);
+				 MYF(0),
+				 "ib*", my_errno,
+				 errbuf);
 		}
 		my_close(fd, MYF(MY_WME));
 	}
@@ -2752,6 +2796,7 @@ innobase_raw_format(
 	return(ut_str_sql_format(buf_tmp, buf_tmp_used, buf, buf_size));
 }
 
+#ifdef MYSQL_COMPRESSION
 /** Check if the string is "empty" or "none".
 @param[in]      algorithm       Compression algorithm to check
 @return true if no algorithm requested */
@@ -2759,7 +2804,9 @@ bool
 Compression::is_none(const char* algorithm)
 {
 	/* NULL is the same as NONE */
-	if (algorithm == NULL || innobase_strcasecmp(algorithm, "none") == 0) {
+	if (algorithm == NULL
+	    || *algorithm == 0
+	    || innobase_strcasecmp(algorithm, "none") == 0) {
 		return(true);
 	}
 
@@ -2805,6 +2852,61 @@ Compression::validate(const char* algorithm)
 
 	return(check(algorithm, &compression));
 }
+#endif /* MYSQL_COMPRESSION */
+
+#ifdef MYSQL_ENCRYPTION
+/** Check if the string is "" or "n".
+ at param[in]      algorithm       Encryption algorithm to check
+ at return true if no algorithm requested */
+bool
+Encryption::is_none(const char* algorithm)
+{
+	/* NULL is the same as NONE */
+	if (algorithm == NULL
+	    || innobase_strcasecmp(algorithm, "n") == 0
+	    || innobase_strcasecmp(algorithm, "") == 0) {
+		return(true);
+	}
+
+	return(false);
+}
+
+/** Check the encryption option and set it
+ at param[in]	option		encryption option
+ at param[in/out]	encryption	The encryption algorithm
+ at return DB_SUCCESS or DB_UNSUPPORTED */
+dberr_t
+Encryption::set_algorithm(
+	const char*	option,
+	Encryption*	encryption)
+{
+	if (is_none(option)) {
+
+		encryption->m_type = NONE;
+
+	} else if (innobase_strcasecmp(option, "y") == 0) {
+
+		encryption->m_type = AES;
+
+	} else {
+		return(DB_UNSUPPORTED);
+	}
+
+	return(DB_SUCCESS);
+}
+
+/** Check for supported ENCRYPT := (Y | N) supported values
+ at param[in]	option		Encryption option
+ at param[out]	encryption	The encryption algorithm
+ at return DB_SUCCESS or DB_UNSUPPORTED */
+dberr_t
+Encryption::validate(const char* option)
+{
+	Encryption	encryption;
+
+	return(encryption.set_algorithm(option, &encryption));
+}
+#endif /* MYSQL_ENCRYPTION */
 
 /*********************************************************************//**
 Compute the next autoinc value.
@@ -3049,6 +3151,7 @@ check_trx_exists(
 	return(trx);
 }
 
+#ifdef MYSQL_REPLACE_TRX_IN_THD
 /** InnoDB transaction object that is currently associated with THD is
 replaced with that of the 2nd argument. The previous value is
 returned through the 3rd argument's buffer, unless it's NULL.  When
@@ -3088,6 +3191,7 @@ innodb_replace_trx_in_thd(
 	}
 	trx = static_cast<trx_t*>(new_trx_arg);
 }
+#endif /* MYSQL_REPLACE_TRX_IN_THD */
 
 /*********************************************************************//**
 Note that a transaction has been registered with MySQL.
@@ -3095,7 +3199,7 @@ Note that a transaction has been registered with MySQL.
 static inline
 bool
 trx_is_registered_for_2pc(
-/*=========================*/
+/*======================*/
 	const trx_t*	trx)	/* in: transaction */
 {
 	return(trx->is_registered == 1);
@@ -3106,7 +3210,7 @@ Note that innobase_commit_ordered() was run. */
 static inline
 void
 trx_set_active_commit_ordered(
-/*==============================*/
+/*==========================*/
 	trx_t*	trx)	/* in: transaction */
 {
 	ut_a(trx_is_registered_for_2pc(trx));
@@ -3553,6 +3657,32 @@ innobase_quote_identifier(
 	}
 }
 
+/** Quote a standard SQL identifier like tablespace, index or column name.
+ at param[in]	trx	InnoDB transaction, or NULL
+ at param[in]	id	identifier to quote
+ at return quoted identifier */
+std::string
+innobase_quote_identifier(
+/*======================*/
+	trx_t*		trx,
+	const char*	id)
+{
+	std::string quoted_identifier;
+	const int	q = trx != NULL && trx->mysql_thd != NULL
+		? get_quote_char_for_identifier(trx->mysql_thd, id, strlen(id))
+		: '`';
+
+	if (q == EOF) {
+		quoted_identifier.append(id);
+	} else {
+		quoted_identifier += (unsigned char)q;
+		quoted_identifier.append(id);
+		quoted_identifier += (unsigned char)q;
+	}
+
+	return (quoted_identifier);
+}
+
 /** Convert a table name to the MySQL system_charset_info (UTF-8)
 and quote it.
 @param[out]	buf	buffer for converted identifier
@@ -3654,7 +3784,7 @@ trx_is_interrupted(
 /*===============*/
 	const trx_t*	trx)	/*!< in: transaction */
 {
-  return(trx && trx->mysql_thd && thd_kill_level(trx->mysql_thd));
+	return(trx && trx->mysql_thd && thd_kill_level(trx->mysql_thd));
 }
 
 /**********************************************************************//**
@@ -3678,9 +3808,17 @@ ha_innobase::reset_template(void)
 	ut_ad(m_prebuilt->magic_n == ROW_PREBUILT_ALLOCATED);
 	ut_ad(m_prebuilt->magic_n2 == m_prebuilt->magic_n);
 
+	/* Force table to be freed in close_thread_table(). */
+	DBUG_EXECUTE_IF("free_table_in_fts_query",
+		if (m_prebuilt->in_fts_query) {
+			table->m_needs_reopen = true;
+		}
+	);
+
 	m_prebuilt->keep_other_fields_on_keyread = 0;
 	m_prebuilt->read_just_key = 0;
 	m_prebuilt->in_fts_query = 0;
+
 	/* Reset index condition pushdown state. */
 	if (m_prebuilt->idx_cond) {
 		m_prebuilt->idx_cond = NULL;
@@ -3797,6 +3935,7 @@ system tables in InnoDB. Please don't add any SE-specific system tables here.
 					layer system table.
 */
 
+#ifdef MYSQL_IS_SUPPORTED_SYSTEM_TABLE
 static bool innobase_is_supported_system_table(const char *db,
 						const char *table_name,
 						bool is_sql_layer_system_table)
@@ -3825,6 +3964,67 @@ static bool innobase_is_supported_system_table(const char *db,
 
 	return false;
 }
+#endif /* MYSQL_IS_SUPPORTED_SYSTEM_TABLE */
+
+#ifdef MYSQL_ENCRYPTION
+/* mutex protecting the master_key_id */
+ib_mutex_t	master_key_id_mutex;
+
+/** Rotate the encrypted tablespace keys according to master key
+rotation.
+ at return false on success, true on failure */
+bool
+innobase_encryption_key_rotation()
+{
+	byte*	master_key = NULL;
+	bool	ret = FALSE;
+
+	/* Require the mutex to block other rotate request. */
+	mutex_enter(&master_key_id_mutex);
+
+	/* Check if keyring loaded and the currently master key
+	can be fetched. */
+	if (Encryption::master_key_id != 0) {
+		ulint			master_key_id;
+		Encryption::Version	version;
+
+		Encryption::get_master_key(&master_key_id,
+					   &master_key,
+					   &version);
+		if (master_key == NULL) {
+			mutex_exit(&master_key_id_mutex);
+			my_error(ER_CANNOT_FIND_KEY_IN_KEYRING, MYF(0));
+			return(true);
+		}
+		my_free(master_key);
+	}
+
+	master_key = NULL;
+
+	/* Generate the new master key. */
+	Encryption::create_master_key(&master_key);
+
+        if (master_key == NULL) {
+		my_error(ER_CANNOT_FIND_KEY_IN_KEYRING, MYF(0));
+		mutex_exit(&master_key_id_mutex);
+                return(true);
+        }
+
+	ret = !fil_encryption_rotate();
+
+	my_free(master_key);
+
+	/* If rotation failure, return error */
+	if (ret) {
+		my_error(ER_CANNOT_FIND_KEY_IN_KEYRING, MYF(0));
+	}
+
+	/* Release the mutex. */
+	mutex_exit(&master_key_id_mutex);
+
+	return(ret);
+}
+#endif /* MYSQL_ENCRYPTION */
 
 /** Return partitioning flags. */
 static uint innobase_partition_flags()
@@ -3922,11 +4122,17 @@ innobase_init(
 	innobase_hton->commit_by_xid = innobase_commit_by_xid;
 	innobase_hton->rollback_by_xid = innobase_rollback_by_xid;
 	innobase_hton->commit_checkpoint_request=innobase_checkpoint_request;
+
+#ifdef INNOBASE_CURSOR_VIEW
 	innobase_hton->create_cursor_read_view = innobase_create_cursor_view;
 	innobase_hton->set_cursor_read_view = innobase_set_cursor_view;
 	innobase_hton->close_cursor_read_view = innobase_close_cursor_view;
+#endif
 	innobase_hton->create = innobase_create_handler;
+
+#ifdef MYSQL_TABLESPACES
 	innobase_hton->alter_tablespace = innobase_alter_tablespace;
+#endif
 	innobase_hton->drop_database = innobase_drop_database;
 	innobase_hton->panic = innobase_end;
 	innobase_hton->partition_flags= innobase_partition_flags;
@@ -3942,10 +4148,12 @@ innobase_init(
 
 	innobase_hton->release_temporary_latches =
 		innobase_release_temporary_latches;
-	/* JAN: TODO: MySQL 5.7
+
+#ifdef MYSQL_REPLACE_TRX_IN_THD
         innobase_hton->replace_native_transaction_in_thd =
                 innodb_replace_trx_in_thd;
-	*/
+#endif
+
 #ifdef WITH_WSREP
         innobase_hton->abort_transaction=wsrep_abort_transaction;
         innobase_hton->set_checkpoint=innobase_wsrep_set_checkpoint;
@@ -3953,21 +4161,28 @@ innobase_init(
         innobase_hton->fake_trx_id=wsrep_fake_trx_id;
 #endif /* WITH_WSREP */
 
-        if (srv_file_per_table)
-          innobase_hton->tablefile_extensions = ha_innobase_exts;
+        if (srv_file_per_table) {
+		innobase_hton->tablefile_extensions = ha_innobase_exts;
+	}
 
-	/* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_INNODB_API_CB
+	/* JAN: TODO: MySQL 5.7 */
 	innobase_hton->data = &innodb_api_cb;
-	*/
+#endif
 
 	innobase_hton->table_options = innodb_table_option_list;
 
 	innodb_remember_check_sysvar_funcs();
 
-	/* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_IS_SUPPORTED_SYSTEM_TABLE
 	innobase_hton->is_supported_system_table=
 		innobase_is_supported_system_table;
-	*/
+#endif
+
+#ifdef MYSQL_ENCRYPTION
+	innobase_hton->rotate_encryption_master_key =
+		innobase_encryption_key_rotation;
+#endif
 
 	ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
 
@@ -4007,6 +4222,7 @@ innobase_init(
 	/* Setup the memory alloc/free tracing mechanisms before calling
 	any functions that could possibly allocate memory. */
 	ut_new_boot();
+
 	if (UNIV_PAGE_SIZE != UNIV_PAGE_SIZE_DEF) {
 		fprintf(stderr,
 			"InnoDB: Warning: innodb_page_size has been "
@@ -4177,7 +4393,7 @@ innobase_init(
 		srv_undo_dir = default_path;
 	}
 
-	os_normalize_path_for_win(srv_undo_dir);
+	os_normalize_path(srv_undo_dir);
 
 	if (strchr(srv_undo_dir, ';')) {
 		sql_print_error("syntax error in innodb_undo_directory");
@@ -4203,6 +4419,11 @@ innobase_init(
 		ib::warn() << deprecated_large_prefix;
 	}
 
+	if (!THDVAR(NULL, support_xa)) {
+		ib::warn() << deprecated_innodb_support_xa_off;
+		THDVAR(NULL, support_xa) = TRUE;
+	}
+
 	if (innobase_file_format_name != innodb_file_format_default) {
 		ib::warn() << deprecated_file_format;
 	}
@@ -4400,16 +4621,18 @@ innobase_init(
 
 	if (innobase_open_files < 10) {
 		innobase_open_files = 300;
-		if (srv_file_per_table && tc_size > 300) {
+		if (srv_file_per_table && tc_size > 300 && tc_size < open_files_limit) {
 			innobase_open_files = tc_size;
 		}
 	}
 
-	if (innobase_open_files > (long) tc_size) {
-		fprintf(stderr,
-                       "innodb_open_files should not be greater"
-                       " than the open_files_limit.\n");
-		innobase_open_files = tc_size;
+	if (innobase_open_files > (long) open_files_limit) {
+		ib::warn() << "innodb_open_files " << innobase_open_files
+			   << " should not be greater"
+			   << "than the open_files_limit " << open_files_limit;
+		if (innobase_open_files > (long) tc_size) {
+			innobase_open_files = tc_size;
+		}
 	}
 
 	srv_max_n_open_files = (ulint) innobase_open_files;
@@ -4433,15 +4656,12 @@ innobase_init(
 	data_mysql_default_charset_coll = (ulint) default_charset_info->number;
 
 	innobase_commit_concurrency_init_default();
-
 #ifdef HAVE_POSIX_FALLOCATE
 	srv_use_posix_fallocate = (ibool) innobase_use_fallocate;
 #endif
 	srv_use_atomic_writes = (ibool) innobase_use_atomic_writes;
-
 	if (innobase_use_atomic_writes) {
 		fprintf(stderr, "InnoDB: using atomic writes.\n");
-
 		/* Force doublewrite buffer off, atomic writes replace it. */
 		if (srv_use_doublewrite_buf) {
 			fprintf(stderr, "InnoDB: Switching off doublewrite buffer "
@@ -4451,7 +4671,7 @@ innobase_init(
 
 		/* Force O_DIRECT on Unixes (on Windows writes are always unbuffered)*/
 #ifndef _WIN32
-		if(!innobase_file_flush_method ||
+		if (!innobase_file_flush_method ||
 			!strstr(innobase_file_flush_method, "O_DIRECT")) {
 			innobase_file_flush_method =
 				srv_file_flush_method_str = (char*)"O_DIRECT";
@@ -4535,6 +4755,11 @@ innobase_init(
 		DBUG_RETURN(innobase_init_abort());
 	}
 
+#ifdef MYSQL_ENCRYPTION
+	/* Create mutex to protect encryption master_key_id. */
+	mutex_create(LATCH_ID_MASTER_KEY_ID_MUTEX, &master_key_id_mutex);
+#endif
+
 	/* Adjust the innodb_undo_logs config object */
 	innobase_undo_logs_init_default_max();
 
@@ -4638,6 +4863,9 @@ innobase_end(
 		hash_table_free(innobase_open_tables);
 		innobase_open_tables = NULL;
 
+#ifdef MYSQL_ENCRYPTION
+		mutex_free(&master_key_id_mutex);
+#endif
 		if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
 			err = 1;
 		}
@@ -4653,44 +4881,6 @@ innobase_end(
 	DBUG_RETURN(err);
 }
 
-/** Flush InnoDB redo logs to the file system.
- at param[in]	hton			InnoDB handlerton
- at param[in]	binlog_group_flush	true if we got invoked by binlog
-group commit during flush stage, false in other cases.
- at return false */
-static
-bool
-innobase_flush_logs(
-	handlerton*	hton,
-	bool		binlog_group_flush)
-{
-	DBUG_ENTER("innobase_flush_logs");
-	DBUG_ASSERT(hton == innodb_hton_ptr);
-
-	if (srv_read_only_mode) {
-		DBUG_RETURN(false);
-	}
-
-	/* If !binlog_group_flush, we got invoked by FLUSH LOGS or similar.
-	Else, we got invoked by binlog group commit during flush stage. */
-
-	if (binlog_group_flush && srv_flush_log_at_trx_commit == 0) {
-		/* innodb_flush_log_at_trx_commit=0
-		(write and sync once per second).
-		Do not flush the redo log during binlog group commit. */
-		DBUG_RETURN(false);
-	}
-
-	/* Flush the redo log buffer to the redo log file.
-	Sync it to disc if we are in FLUSH LOGS, or if
-	innodb_flush_log_at_trx_commit=1
-	(write and sync at each commit). */
-	log_buffer_flush_to_disk(!binlog_group_flush
-				 || srv_flush_log_at_trx_commit == 1);
-
-	DBUG_RETURN(false);
-}
-
 /*****************************************************************//**
 Commits a transaction in an InnoDB database. */
 void
@@ -4783,7 +4973,7 @@ innobase_start_trx_and_assign_read_view(
 static
 void
 innobase_commit_ordered_2(
-/*============*/
+/*======================*/
 	trx_t*	trx, 	/*!< in: Innodb transaction */
 	THD*	thd)	/*!< in: MySQL thread handle */
 {
@@ -4872,7 +5062,7 @@ the one handling the rest of the transaction. */
 static
 void
 innobase_commit_ordered(
-/*============*/
+/*====================*/
 	handlerton *hton, /*!< in: Innodb handlerton */
 	THD*	thd,	/*!< in: MySQL thread handle of the user for whom
 			the transaction should be committed */
@@ -4892,7 +5082,7 @@ innobase_commit_ordered(
 	have an assert here.*/
 	ut_ad(!trx->has_search_latch);
 
-        if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) {
+	if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) {
 		/* We cannot throw error here; instead we will catch this error
 		again in innobase_commit() and report it from there. */
 		DBUG_VOID_RETURN;
@@ -4937,7 +5127,10 @@ innobase_commit(
 
 	if (trx_in_innodb.is_aborted()) {
 
-		DBUG_RETURN(innobase_rollback(hton, thd, commit_trx));
+		innobase_rollback(hton, thd, commit_trx);
+
+		DBUG_RETURN(convert_error_code_to_mysql(
+			DB_FORCED_ABORT, 0, thd));
 	}
 
 	ut_ad(trx->dict_operation_lock_mode == 0);
@@ -4955,6 +5148,7 @@ innobase_commit(
 	}
 
 	bool	read_only = trx->read_only || trx->id == 0;
+	DBUG_PRINT("info", ("readonly: %d", read_only));
 
 	if (commit_trx
 	    || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
@@ -4965,6 +5159,7 @@ innobase_commit(
 		/* Run the fast part of commit if we did not already. */
 		if (!trx_is_active_commit_ordered(trx)) {
 			innobase_commit_ordered_2(trx, thd);
+
 		}
 
 		/* We were instructed to commit the whole transaction, or
@@ -4975,11 +5170,14 @@ innobase_commit(
 		this one, to allow then to group commit with us. */
 		thd_wakeup_subsequent_commits(thd, 0);
 
+		if (!read_only) {
+			trx->flush_log_later = false;
+		}
+
 		/* Now do a write + flush of logs. */
 		trx_commit_complete_for_mysql(trx);
 
 		trx_deregister_from_2pc(trx);
-
 	} else {
 		/* We just mark the SQL statement ended and do not do a
 		transaction commit */
@@ -5062,7 +5260,7 @@ innobase_rollback(
 		error = trx_rollback_for_mysql(trx);
 
 		if (trx->state == TRX_STATE_FORCED_ROLLBACK) {
-
+#ifdef UNIV_DEBUG
 			char	buffer[1024];
 
 			/* JAN: TODO: MySQL 5.7
@@ -5073,18 +5271,12 @@ innobase_rollback(
 			*/
 			thd_get_error_context_description(thd, buffer,
 				sizeof(buffer), 512);
-
-			error = DB_FORCED_ABORT;
+#endif /* UNIV_DEBUG */
 
 			trx->state = TRX_STATE_NOT_STARTED;
 		}
 
 		trx_deregister_from_2pc(trx);
-
-	} else if (trx_in_innodb.is_aborted()) {
-
-		error = DB_FORCED_ABORT;
-
 	} else {
 
 		error = trx_rollback_last_sql_stat_for_mysql(trx);
@@ -5207,7 +5399,7 @@ checkpoint when necessary.*/
 UNIV_INTERN
 void
 innobase_mysql_log_notify(
-/*===============*/
+/*======================*/
 	ib_uint64_t	write_lsn,	/*!< in: LSN written to log file */
 	ib_uint64_t	flush_lsn)	/*!< in: LSN flushed to disk */
 {
@@ -5336,7 +5528,7 @@ innobase_rollback_to_savepoint_can_release_mdl(
 
 	TrxInInnoDB	trx_in_innodb(trx);
 
-        /* If transaction has not acquired any locks then it is safe
+	/* If transaction has not acquired any locks then it is safe
 	to release MDL after rollback to savepoint */
 	if (UT_LIST_GET_LEN(trx->lock.trx_locks) == 0) {
 
@@ -5441,38 +5633,87 @@ innobase_close_connection(
 	DBUG_ASSERT(hton == innodb_hton_ptr);
 
 	trx_t*	trx = thd_to_trx(thd);
+	bool	free_trx = false;
+
+	/* During server initialization MySQL layer will try to open
+	some of the master-slave tables those residing in InnoDB.
+	After MySQL layer is done with needed checks these tables
+	are closed followed by invocation of close_connection on the
+	associated thd.
+
+	close_connection rolls back the trx and then frees it.
+	Once trx is freed thd should avoid maintaining reference to
+	it else it can be classified as stale reference.
+
+	Re-invocation of innodb_close_connection on same thd should
+	get trx as NULL. */
 
 	if (trx) {
 
 		TrxInInnoDB	trx_in_innodb(trx);
 
+		if (trx_in_innodb.is_aborted()) {
+
+			while (trx_is_started(trx)) {
+
+				os_thread_sleep(20);
+			}
+		}
+
 		if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) {
 
 			sql_print_error("Transaction not registered for MySQL 2PC, "
 				"but transaction is active");
 		}
 
-		if (trx_is_started(trx) && global_system_variables.log_warnings) {
-
+		/* Disconnect causes rollback in the following cases:
+		- trx is not started, or
+		- trx is in *not* in PREPARED state, or
+		- trx has not updated any persistent data.
+		TODO/FIXME: it does not make sense to initiate rollback
+		in the 1st and 3rd case. */
+		if (trx_is_started(trx)) {
+			if (trx_state_eq(trx, TRX_STATE_PREPARED)) {
+				if (trx_is_redo_rseg_updated(trx)) {
+					trx_disconnect_prepared(trx);
+				} else {
+					trx_rollback_for_mysql(trx);
+					trx_deregister_from_2pc(trx);
+					free_trx = true;
+				}
+			} else {
 			sql_print_warning(
 				"MySQL is closing a connection that has an active "
 				"InnoDB transaction.  " TRX_ID_FMT " row modifications "
 				"will roll back.",
-				trx->undo_no);
+					" row modifications will roll back.",
+					trx->undo_no);
+				ut_d(ib::warn()
+				     << "trx: " << trx << " started on: "
+				     << innobase_basename(trx->start_file)
+				     << ":" << trx->start_line);
+				innobase_rollback_trx(trx);
+				free_trx = true;
+			}
+		} else {
+			innobase_rollback_trx(trx);
+			free_trx = true;
 		}
+	}
 
-		innobase_rollback_trx(trx);
-
+	/* Free trx only after TrxInInnoDB is deleted. */
+	if (free_trx) {
 		trx_free_for_mysql(trx);
+	}
 
-		UT_DELETE(thd_to_innodb_session(thd));
+	UT_DELETE(thd_to_innodb_session(thd));
 
-		thd_to_innodb_session(thd) = NULL;
-	}
+	thd_to_innodb_session(thd) = NULL;
 
 	DBUG_RETURN(0);
 }
 
+#ifdef MYSQL_KILL_CONNECTION
 /*****************************************************************//**
 Cancel any pending lock request associated with the current THD. */
 static
@@ -5491,11 +5732,17 @@ innobase_kill_connection(
 	if (trx != NULL) {
 
 		/* Cancel a pending lock request if there are any */
-		lock_trx_handle_wait(trx, false, false);
+		dberr_t err = lock_trx_handle_wait(trx, false, false);
+
+		if (err != DB_SUCCESS && err != DB_LOCK_WAIT) {
+			ib::warn() << "Killing connection failed " << ut_strerr(err) << "("<<err<<")";
+		}
+
 	}
 
 	DBUG_VOID_RETURN;
 }
+#endif /* MYSQL_KILL_CONNECTION */
 
 UNIV_INTERN void lock_cancel_waiting_and_release(lock_t* lock);
 
@@ -5504,10 +5751,10 @@ Cancel any pending lock request associated with the current THD. */
 static
 void
 innobase_kill_query(
-/*======================*/
-        handlerton*	hton,	    /*!< in: innobase handlerton */
-	THD*	thd,	            /*!< in: MySQL thread being killed */
-        enum thd_kill_levels level) /*!< in: kill level */
+/*================*/
+	handlerton*	hton,		/*!< in: innobase handlerton */
+	THD*		thd,		/*!< in: MySQL thread being killed */
+	enum thd_kill_levels level)	/*!< in: kill level */
 {
 	trx_t*	trx;
 
@@ -5537,10 +5784,10 @@ innobase_kill_query(
 		bool trx_mutex_taken = false;
 		bool already_have_lock_mutex = false;
 		bool already_have_trx_mutex = false;
-		dberr_t err;
+		dberr_t err = DB_SUCCESS;
 
 		if (trx->lock.wait_lock) {
-			WSREP_DEBUG("Killing victim trx %p BF %d trx BF %d trx_id %lu ABORT %d thd %p"
+			WSREP_DEBUG("Killing victim trx %p BF %d trx BF %d trx_id " IB_ID_FMT " ABORT %d thd %p"
 				" current_thd %p BF %d",
 				trx, wsrep_thd_is_BF(trx->mysql_thd, FALSE),
 				wsrep_thd_is_BF(thd, FALSE),
@@ -5580,6 +5827,10 @@ innobase_kill_query(
 			ut_ad(trx_mutex_own(trx));
 			trx_mutex_exit(trx);
 		}
+
+		if (err != DB_SUCCESS && err != DB_LOCK_WAIT) {
+			ib::warn() << "Killing connection failed " << ut_strerr(err) << "("<<err<<")";
+		}
 	}
 
 	DBUG_VOID_RETURN;
@@ -5805,16 +6056,19 @@ Determines if the primary key is clustered index.
 
 bool
 ha_innobase::primary_key_is_clustered()
-/*=========================================*/
+/*===================================*/
 {
 	return(true);
 }
 
-/*********************************************************************
-Normalizes a table name string. A normalized name consists of the
-database name catenated to '/' and table name. An example:
-test/mytable. On Windows normalization puts both the database name and the
-table name always to lower case if "set_lower_case" is set to TRUE. */
+/** Normalizes a table name string.
+A normalized name consists of the database name catenated to '/'
+and table name. For example: test/mytable.
+On Windows, normalization puts both the database name and the
+table name always to lower case if "set_lower_case" is set to TRUE.
+ at param[out]	norm_name	Normalized name, null-terminated.
+ at param[in]	name		Name to normalize.
+ at param[in]	set_lower_case	True if we also should fold to lower case. */
 void
 normalize_table_name_c_low(
 /*=======================*/
@@ -6076,11 +6330,12 @@ innobase_match_index_columns(
 			mtype = innodb_idx_fld->col->mtype;
 		}
 
-                // MariaDB-5.5 compatibility
-                if ((key_part->field->real_type() == MYSQL_TYPE_ENUM ||
-                     key_part->field->real_type() == MYSQL_TYPE_SET) &&
-                    mtype == DATA_FIXBINARY)
-                  col_type= DATA_FIXBINARY;
+		/* MariaDB-5.5 compatibility */
+		if ((key_part->field->real_type() == MYSQL_TYPE_ENUM ||
+		     key_part->field->real_type() == MYSQL_TYPE_SET) &&
+		    mtype == DATA_FIXBINARY) {
+			col_type= DATA_FIXBINARY;
+		}
 
 		if (col_type != mtype) {
 			/* If the col_type we get from mysql type is a geometry
@@ -6116,6 +6371,7 @@ innobase_match_index_columns(
 	DBUG_RETURN(TRUE);
 }
 
+#ifdef MYSQL_VIRTUAL_COLUMNS
 /** Build a template for a base column for a virtual column
 @param[in]	table		MySQL TABLE
 @param[in]	clust_index	InnoDB clustered index
@@ -6197,13 +6453,13 @@ is done when the table first opened.
 @param[in,out]	s_templ		InnoDB template structure
 @param[in]	add_v		new virtual columns added along with
 				add index call
- at param[in]	locked		true if innobase_share_mutex is held
+ at param[in]	locked		true if dict_sys mutex is held
 @param[in]	share_tbl_name	original MySQL table name */
 void
 innobase_build_v_templ(
 	const TABLE*		table,
 	const dict_table_t*	ib_table,
-	innodb_col_templ_t*	s_templ,
+	dict_vcol_templ_t*	s_templ,
 	const dict_add_v_col_t*	add_v,
 	bool			locked,
 	const char*		share_tbl_name)
@@ -6221,12 +6477,12 @@ innobase_build_v_templ(
 	ut_ad(n_v_col > 0);
 
 	if (!locked) {
-		mysql_mutex_lock(&innobase_share_mutex);
+		mutex_enter(&dict_sys->mutex);
 	}
 
 	if (s_templ->vtempl) {
 		if (!locked) {
-			mysql_mutex_unlock(&innobase_share_mutex);
+			mutex_exit(&dict_sys->mutex);
 		}
 		return;
 	}
@@ -6239,7 +6495,14 @@ innobase_build_v_templ(
 	s_templ->n_col = ncol;
 	s_templ->n_v_col = n_v_col;
 	s_templ->rec_len = table->s->stored_rec_length;
-	s_templ->default_rec = table->s->default_values;
+	// JAN: MySQL 5.6
+	// s_templ->default_rec = table->s->default_values;
+
+	s_templ->default_rec = static_cast<byte*>(
+		ut_malloc_nokey(table->s->stored_rec_length));
+	memcpy(s_templ->default_rec, table->s->default_values,
+	       table->s->stored_rec_length);
+
 
 	/* Mark those columns could be base columns */
 	for (ulint i = 0; i < ib_table->n_v_cols; i++) {
@@ -6334,24 +6597,17 @@ innobase_build_v_templ(
 	}
 
 	if (!locked) {
-		mysql_mutex_unlock(&innobase_share_mutex);
+		mutex_exit(&dict_sys->mutex);
 	}
 
-	ut_strlcpy(s_templ->db_name, table->s->db.str,
-		   table->s->db.length + 1);
-	s_templ->db_name[table->s->db.length] = 0;
-
-	ut_strlcpy(s_templ->tb_name, table->s->table_name.str,
-		   table->s->table_name.length + 1);
-	s_templ->tb_name[table->s->table_name.length] = 0;
+	s_templ->db_name = table->s->db.str;
+	s_templ->tb_name = table->s->table_name.str;
 
 	if (share_tbl_name) {
-		ulint	s_len = strlen(share_tbl_name);
-		ut_strlcpy(s_templ->share_name, share_tbl_name,
-			   s_len + 1);
-		s_templ->tb_name[s_len] = 0;
+		s_templ->share_name = share_tbl_name;
 	}
 }
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 
 /*******************************************************************//**
 This function builds a translation table in INNOBASE_SHARE
@@ -6577,6 +6833,7 @@ ha_innobase::innobase_initialize_autoinc()
 		auto_inc = field->get_max_int_value();
 		*/
 		auto_inc = innobase_get_int_col_max_value(field);
+		ut_ad(!innobase_is_v_fld(field));
 
 		/* autoinc column cannot be virtual column */
 		ut_ad(!innobase_is_v_fld(field));
@@ -6681,25 +6938,6 @@ ha_innobase::innobase_initialize_autoinc()
 	dict_table_autoinc_initialize(m_prebuilt->table, auto_inc);
 }
 
-/** Free the virtual column template
- at param[in,out]	vc_templ	virtual column template */
-void
-free_vc_templ(
-	innodb_col_templ_t*	vc_templ)
-{
-	if (vc_templ->vtempl) {
-		ut_ad(vc_templ->n_v_col);
-		for (ulint i = 0; i < vc_templ->n_col
-		     + vc_templ->n_v_col ; i++) {
-			if (vc_templ->vtempl[i]) {
-				ut_free(vc_templ->vtempl[i]);
-			}
-		}
-		ut_free(vc_templ->vtempl);
-		vc_templ->vtempl = NULL;
-	}
-}
-
 /*****************************************************************//**
 Creates and opens a handle to a table which already exists in an InnoDB
 database.
@@ -6782,7 +7020,7 @@ ha_innobase::open(
 
 		ib::warn() << "Table " << norm_name << " contains "
 			<< dict_table_get_n_user_cols(ib_table) << " user"
-			" defined columns in InnoDB, but " << table->s->fields
+			" defined columns in InnoDB, but " << table->s->stored_fields
 			<< " columns in MySQL. Please check"
 			" INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and " REFMAN
 			"innodb-troubleshooting.html for how to resolve the"
@@ -6796,6 +7034,28 @@ ha_innobase::open(
 		is_part = NULL;
 	}
 
+#ifdef MYSQL_ENCRYPTION
+	/* For encrypted table, check if the encryption info in data
+	file can't be retrieved properly, mark it as corrupted. */
+	if (ib_table != NULL
+	    && dict_table_is_encrypted(ib_table)
+	    && ib_table->ibd_file_missing
+	    && !dict_table_is_discarded(ib_table)) {
+
+		/* Mark this table as corrupted, so the drop table
+		or force recovery can still use it, but not others. */
+
+		dict_table_close(ib_table, FALSE, FALSE);
+		ib_table = NULL;
+		is_part = NULL;
+
+		free_share(m_share);
+		my_error(ER_CANNOT_FIND_KEY_IN_KEYRING, MYF(0));
+
+		DBUG_RETURN(HA_ERR_TABLE_CORRUPT);
+	}
+#endif
+
 	if (NULL == ib_table) {
 
 		if (is_part) {
@@ -6860,26 +7120,6 @@ ha_innobase::open(
 		no_tablespace = false;
 	}
 
-	if (dict_table_has_fts_index(ib_table)) {
-
-		/* Check if table is in a consistent state.
-		Crash during truncate can put table in an inconsistent state. */
-		trx_t*	trx = innobase_trx_allocate(ha_thd());
-		bool	sane = fts_is_corrupt(ib_table, trx);
-		innobase_commit_low(trx);
-		trx_free_for_mysql(trx);
-		trx = NULL;
-
-		if (!sane) {
-			/* In-consistent fts index found. */
-			free_share(m_share);
-			set_my_errno(ENOENT);
-
-			dict_table_close(ib_table, FALSE, FALSE);
-			DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
-		}
-	}
-
 	if (!thd_tablespace_op(thd) && no_tablespace) {
 		free_share(m_share);
 		set_my_errno(ENOENT);
@@ -6931,29 +7171,35 @@ ha_innobase::open(
 	m_prebuilt->default_rec = table->s->default_values;
 	ut_ad(m_prebuilt->default_rec);
 
+	m_prebuilt->m_mysql_table = table;
+
 	/* Looks like MySQL-3.23 sometimes has primary key number != 0 */
 	m_primary_key = table->s->primary_key;
 
 	key_used_on_scan = m_primary_key;
 
+#ifdef MYSQL_VIRTUAL_COLUMNS
 	if (ib_table->n_v_cols) {
-		if (!m_share->s_templ.vtempl) {
+		mutex_enter(&dict_sys->mutex);
+		if (ib_table->vc_templ == NULL) {
+			ib_table->vc_templ = UT_NEW_NOKEY(dict_vcol_templ_t());
+			ib_table->vc_templ->vtempl = NULL;
+		} else if (ib_table->get_ref_count() == 1) {
+			/* Clean and refresh the template if no one else
+			get hold on it */
+			dict_free_vc_templ(ib_table->vc_templ);
+			ib_table->vc_templ->vtempl = NULL;
+		}
+
+		if (ib_table->vc_templ->vtempl == NULL) {
 			innobase_build_v_templ(
-				table, ib_table, &(m_share->s_templ), NULL,
-				false, m_share->table_name);
-
-			mysql_mutex_lock(&innobase_share_mutex);
-			if (ib_table->vc_templ
-			    && ib_table->vc_templ_purge) {
-				free_vc_templ(ib_table->vc_templ);
-				ut_free(ib_table->vc_templ);
-			}
-			mysql_mutex_unlock(&innobase_share_mutex);
+				table, ib_table, ib_table->vc_templ, NULL,
+				true, m_share->table_name);
 		}
-		ib_table->vc_templ = &m_share->s_templ;
-	} else {
-		ib_table->vc_templ = NULL;
+
+		mutex_exit(&dict_sys->mutex);
 	}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 
 	if (!innobase_build_index_translation(table, ib_table, m_share)) {
 		  sql_print_error("Build InnoDB index translation table for"
@@ -7085,9 +7331,9 @@ ha_innobase::open(
 		dict_table_autoinc_unlock(m_prebuilt->table);
 	}
 
+#if MYSQL_PLUGIN_FULLTEXT_PARSER
 	/* Set plugin parser for fulltext index */
 	for (uint i = 0; i < table->s->keys; i++) {
-		/* JAN: TODO: MySQL 5.7 FT Parser
 		if (table->key_info[i].flags & HA_USES_PARSER) {
 			dict_index_t*	index = innobase_get_index(i);
 			plugin_ref	parser = table->key_info[i].parser;
@@ -7105,47 +7351,37 @@ ha_innobase::open(
 			DBUG_EXECUTE_IF("fts_instrument_use_default_parser",
 				index->parser = &fts_default_parser;);
 		}
-		*/
 	}
+#endif
 
 	info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
 
-	/* We don't support compression for the system tablespace and
-	the temporary tablespace. Only because they are shared tablespaces.
-	There is no other technical reason. */
-
-	if (m_prebuilt->table != NULL
-	    && !m_prebuilt->table->ibd_file_missing
-	    && !is_shared_tablespace(m_prebuilt->table->space)) {
-
-		/* JAN: TODO: MySQL 5.7: Table options should be used here
-		dberr_t	err = fil_set_compression(
-			m_prebuilt->table->space, table->s->compress.str);
-		*/
-		dberr_t err = DB_SUCCESS;
+#ifdef MYSQL_COMPRESSION // MySQL 5.7 Compression
+	dberr_t	err = fil_set_compression(m_prebuilt->table,
+					  table->s->compress.str);
 
-		switch (err) {
-		case DB_NOT_FOUND:
-		case DB_UNSUPPORTED:
-			/* We will do another check before the create
-			table and push the error to the client there. */
-			break;
+	switch (err) {
+	case DB_NOT_FOUND:
+	case DB_UNSUPPORTED:
+		/* We will do another check before the create
+		table and push the error to the client there. */
+		break;
 
-		case DB_IO_NO_PUNCH_HOLE_TABLESPACE:
-			/* We did the check in the 'if' above. */
+	case DB_IO_NO_PUNCH_HOLE_TABLESPACE:
+		/* We did the check in the 'if' above. */
 
-		case DB_IO_NO_PUNCH_HOLE_FS:
-			/* During open we can't check whether the FS supports
-			punch hole or not, at least on Linux. */
-			break;
+	case DB_IO_NO_PUNCH_HOLE_FS:
+		/* During open we can't check whether the FS supports
+		punch hole or not, at least on Linux. */
+		break;
 
-		default:
-			ut_error;
+	default:
+		ut_error;
 
-		case DB_SUCCESS:
-			break;
-		}
+	case DB_SUCCESS:
+		break;
 	}
+#endif
 
 	DBUG_RETURN(0);
 }
@@ -7327,7 +7563,7 @@ get_field_offset(
 UNIV_INTERN
 int
 wsrep_innobase_mysql_sort(
-/*===============*/
+/*======================*/
 					/* out: str contains sort string */
 	int		mysql_type,	/* in: MySQL type */
 	uint		charset_number,	/* in: number of the charset */
@@ -7384,8 +7620,8 @@ wsrep_innobase_mysql_sort(
 		memcpy(tmp_str, str, str_length);
 
 		tmp_length = charset->coll->strnxfrm(charset, str, str_length,
-                                             str_length, tmp_str,
-                                             tmp_length, 0);
+						     str_length, tmp_str,
+						     tmp_length, 0);
 		DBUG_ASSERT(tmp_length <= str_length);
 		if (wsrep_protocol_version < 3) {
 			tmp_length = charset->coll->strnxfrm(
@@ -7680,7 +7916,8 @@ get_innobase_type_from_mysql_type(
 			return(DATA_VARMYSQL);
 		}
 	case MYSQL_TYPE_BIT:
-	case MYSQL_TYPE_STRING: if (field->binary()) {
+	case MYSQL_TYPE_STRING:
+		if (field->binary()) {
 
 			return(DATA_FIXBINARY);
 		} else if (strcmp(field->charset()->name,
@@ -7700,13 +7937,14 @@ get_innobase_type_from_mysql_type(
 	case MYSQL_TYPE_YEAR:
 	case MYSQL_TYPE_NEWDATE:
 		return(DATA_INT);
-	case MYSQL_TYPE_TIMESTAMP:
 	case MYSQL_TYPE_TIME:
 	case MYSQL_TYPE_DATETIME:
-		if (field->key_type() == HA_KEYTYPE_BINARY)
+	case MYSQL_TYPE_TIMESTAMP:
+		if (field->key_type() == HA_KEYTYPE_BINARY) {
 			return(DATA_FIXBINARY);
-                else
+		} else {
 			return(DATA_INT);
+		}
 	case MYSQL_TYPE_FLOAT:
 		return(DATA_FLOAT);
 	case MYSQL_TYPE_DOUBLE:
@@ -7851,8 +8089,8 @@ wsrep_store_key_val_for_row(
 				true_len = (ulint) cs->cset->well_formed_len(cs,
 						(const char *) data,
 						(const char *) data + len,
-                                                (uint) (key_len /
-                                                        cs->mbmaxlen),
+						(uint) (key_len /
+						cs->mbmaxlen),
 						&error);
 			}
 
@@ -7867,13 +8105,12 @@ wsrep_store_key_val_for_row(
 			true_len = wsrep_innobase_mysql_sort(
 				mysql_type, cs->number, sorted, true_len,
 				REC_VERSION_56_MAX_INDEX_COL_LEN);
-
 			if (wsrep_protocol_version > 1) {
-			/* Note that we always reserve the maximum possible
-			   length of the true VARCHAR in the key value, though
-			   only len first bytes after the 2 length bytes contain
-			   actual data. The rest of the space was reset to zero
-			   in the bzero() call above. */
+				/* Note that we always reserve the maximum possible
+				length of the true VARCHAR in the key value, though
+				only len first bytes after the 2 length bytes contain
+				actual data. The rest of the space was reset to zero
+				in the bzero() call above. */
 				if (true_len > buff_space) {
 					fprintf (stderr,
 						 "WSREP: key truncated: %s\n",
@@ -7881,11 +8118,11 @@ wsrep_store_key_val_for_row(
 					true_len = buff_space;
 				}
  				memcpy(buff, sorted, true_len);
-                                buff       += true_len;
+				buff += true_len;
 				buff_space -= true_len;
-                        } else {
-                                buff += key_len;
-                        }
+			} else {
+				buff += key_len;
+			}
 		} else if (mysql_type == MYSQL_TYPE_TINY_BLOB
 			|| mysql_type == MYSQL_TYPE_MEDIUM_BLOB
 			|| mysql_type == MYSQL_TYPE_BLOB
@@ -7939,8 +8176,8 @@ wsrep_store_key_val_for_row(
 						(const char *) blob_data,
 						(const char *) blob_data
 							+ blob_len,
-                                                (uint) (key_len /
-                                                        cs->mbmaxlen),
+						(uint) (key_len /
+							cs->mbmaxlen),
 						&error);
 			}
 
@@ -7960,7 +8197,7 @@ wsrep_store_key_val_for_row(
 
 			/* Note that we always reserve the maximum possible
 			length of the BLOB prefix in the key value. */
-                        if (wsrep_protocol_version > 1) {
+			if (wsrep_protocol_version > 1) {
 				if (true_len > buff_space) {
 					fprintf (stderr,
 						 "WSREP: key truncated: %s\n",
@@ -8028,8 +8265,8 @@ wsrep_store_key_val_for_row(
 							(const char *)src_start,
 							(const char *)src_start
 								+ key_len,
-                                                        (uint) (key_len /
-                                                                cs->mbmaxlen),
+							(uint) (key_len /
+								cs->mbmaxlen),
 							&error);
 				}
 				memcpy(sorted, src_start, true_len);
@@ -8057,7 +8294,6 @@ wsrep_store_key_val_for_row(
 	DBUG_RETURN((uint)(buff - buff_start));
 }
 #endif /* WITH_WSREP */
-
 /**************************************************************//**
 Determines if a field is needed in a m_prebuilt struct 'template'.
 @return field to use, or NULL if the field is not needed */
@@ -8083,7 +8319,7 @@ build_template_needs_field(
 	dict_index_t*	index,		/*!< in: InnoDB index to use */
 	const TABLE*	table,		/*!< in: MySQL table object */
 	ulint		i,		/*!< in: field index in InnoDB table */
-        ulint		sql_idx,	/*!< in: field index in SQL table */
+	ulint		sql_idx,	/*!< in: field index in SQL table */
 	ulint		num_v)		/*!< in: num virtual column so far */
 {
 	const Field*	field	= table->field[sql_idx];
@@ -8340,7 +8576,8 @@ ha_innobase::build_template(
 	/* Below we check column by column if we need to access
 	the clustered index. */
 
-        n_stored_fields= (ulint)table->s->stored_fields; /* number of stored columns */
+	/* number of stored columns */
+	n_stored_fields= (ulint)table->s->stored_fields;
 
 	if (!m_prebuilt->mysql_template) {
 		m_prebuilt->mysql_template = (mysql_row_templ_t*)
@@ -8369,7 +8606,7 @@ ha_innobase::build_template(
 		for (i = 0, sql_idx = 0; i < n_stored_fields; i++, sql_idx++) {
 			ibool		index_contains;
 
-                        while (!table->field[sql_idx]->stored_in_db()) {
+			while (!table->field[sql_idx]->stored_in_db()) {
 				sql_idx++;
 			}
 
@@ -8514,9 +8751,9 @@ ha_innobase::build_template(
 			mysql_row_templ_t*	templ;
 			ibool			index_contains;
 
-                        while (!table->field[sql_idx]->stored_in_db()) {
-			        sql_idx++;
-                        }
+			while (!table->field[sql_idx]->stored_in_db()) {
+				sql_idx++;
+			}
 
 			if (innobase_is_v_fld(table->field[sql_idx])) {
 				index_contains = dict_index_contains_col_or_prefix(
@@ -8571,9 +8808,9 @@ ha_innobase::build_template(
 		for (i = 0, sql_idx = 0; i < n_stored_fields; i++, sql_idx++) {
 			const Field*	field;
 
-                        while (!table->field[sql_idx]->stored_in_db()) {
-			        sql_idx++;
-                        }
+			while (!table->field[sql_idx]->stored_in_db()) {
+				sql_idx++;
+			}
 
 			if (whole_row) {
 				/* Even this is whole_row, if the seach is
@@ -8587,13 +8824,13 @@ ha_innobase::build_template(
 				    && !dict_index_contains_col_or_prefix(
 					m_prebuilt->index, num_v, true))
 				{
-					ut_ad(!bitmap_is_set(
-						table->read_set, i));
-					ut_ad(!bitmap_is_set(
-						table->write_set, i));
-
+					/* Turn off ROW_MYSQL_WHOLE_ROW */
+					m_prebuilt->template_type =
+						 ROW_MYSQL_REC_FIELDS;
+					num_v++;
 					continue;
 				}
+
 				field = table->field[sql_idx];
 			} else {
 				ibool	contain;
@@ -8607,6 +8844,7 @@ ha_innobase::build_template(
 						false);
 				}
 
+
 				field = build_template_needs_field(
 					contain,
 					m_prebuilt->read_just_key,
@@ -8656,6 +8894,7 @@ dberr_t
 ha_innobase::innobase_lock_autoinc(void)
 /*====================================*/
 {
+	DBUG_ENTER("ha_innobase::innobase_lock_autoinc");
 	dberr_t		error = DB_SUCCESS;
 	long		lock_mode = innobase_autoinc_lock_mode;
 
@@ -8702,6 +8941,8 @@ ha_innobase::innobase_lock_autoinc(void)
 		/* Fall through to old style locking. */
 
 	case AUTOINC_OLD_STYLE_LOCKING:
+		DBUG_EXECUTE_IF("die_if_autoinc_old_lock_style_used",
+				ut_ad(0););
 		error = row_lock_table_autoinc_for_mysql(m_prebuilt);
 
 		if (error == DB_SUCCESS) {
@@ -8715,7 +8956,7 @@ ha_innobase::innobase_lock_autoinc(void)
 		ut_error;
 	}
 
-	return(error);
+	DBUG_RETURN(error);
 }
 
 /********************************************************************//**
@@ -8778,7 +9019,7 @@ ha_innobase::write_row(
 {
 	dberr_t		error;
 #ifdef WITH_WSREP
-	ibool           auto_inc_inserted= FALSE; /* if NULL was inserted */
+	ibool		auto_inc_inserted= FALSE; /* if NULL was inserted */
 #endif
 	ulint		sql_command;
 	int		error_result = 0;
@@ -8796,7 +9037,10 @@ ha_innobase::write_row(
 	if (!dict_table_is_intrinsic(m_prebuilt->table)
 	    && trx_in_innodb.is_aborted()) {
 
-		DBUG_RETURN(innobase_rollback(ht, m_user_thd, false));
+		innobase_rollback(ht, m_user_thd, false);
+
+		DBUG_RETURN(convert_error_code_to_mysql(
+			DB_FORCED_ABORT, 0, m_user_thd));
 	}
 
 	/* Step-1: Validation checks before we commence write_row operation. */
@@ -9139,8 +9383,7 @@ ha_innobase::write_row(
 	    wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE &&
 	    wsrep_on(m_user_thd)                           &&
 	    !wsrep_consistency_check(m_user_thd)           &&
-	    !wsrep_thd_ignore_table(m_user_thd))
-	{
+	    !wsrep_thd_ignore_table(m_user_thd)) {
 		if (wsrep_append_keys(m_user_thd, false, record, NULL))
 		{
 			DBUG_PRINT("wsrep", ("row key failed"));
@@ -9240,7 +9483,7 @@ calc_row_difference(
         uint		sql_idx,i, innodb_idx= 0;
 	ibool		changes_fts_column = FALSE;
 	ibool		changes_fts_doc_col = FALSE;
-	trx_t*          trx = thd_to_trx(thd);
+	trx_t*		trx = thd_to_trx(thd);
 	doc_id_t	doc_id = FTS_NULL_DOC_ID;
 	ulint		num_v = 0;
 
@@ -9342,12 +9585,34 @@ calc_row_difference(
 			}
 		}
 
+#ifdef UNIV_DEBUG
+		bool	online_ord_part = false;
+#endif
+
 		if (is_virtual) {
 			/* If the virtual column is not indexed,
 			we shall ignore it for update */
 			if (!col->ord_part) {
-			       num_v++;
-			       continue;
+				/* Check whether there is a table-rebuilding
+				online ALTER TABLE in progress, and this
+				virtual column could be newly indexed, thus
+				it will be materialized. Then we will have
+				to log its update.
+				Note, we do not support online dropping virtual
+				column while adding new index, nor with
+				online alter column order while adding index,
+				so the virtual column sequence must not change
+				if it is online operation */
+				if (dict_index_is_online_ddl(clust_index)
+				    && row_log_col_is_indexed(clust_index,
+							      num_v)) {
+#ifdef UNIV_DEBUG
+					online_ord_part = true;
+#endif
+				} else {
+					num_v++;
+					continue;
+				}
 			}
 
 			if (!uvect->old_vrow) {
@@ -9423,7 +9688,7 @@ calc_row_difference(
 				upd_fld_set_virtual_col(ufield);
 				ufield->field_no = num_v;
 
-				ut_ad(col->ord_part);
+				ut_ad(col->ord_part || online_ord_part);
 				ufield->old_v_val = static_cast<dfield_t*>(
 					mem_heap_alloc(
 						uvect->heap,
@@ -9500,12 +9765,12 @@ calc_row_difference(
 				prebuilt, vfield, o_len,
 				col, old_mysql_row_col,
 				col_pack_len, buf);
-			ut_ad(col->ord_part);
+			ut_ad(col->ord_part || online_ord_part);
 			num_v++;
 		}
 
-                if (field->stored_in_db()) {
-                  innodb_idx++;
+		if (field->stored_in_db()) {
+			innodb_idx++;
 		}
 	}
 
@@ -9584,7 +9849,7 @@ calc_row_difference(
 
 	ut_a(buf <= (byte*) original_upd_buff + buff_len);
 
-        ut_ad(uvect->validate());
+	ut_ad(uvect->validate());
 	return(DB_SUCCESS);
 }
 
@@ -9609,7 +9874,7 @@ wsrep_calc_row_hash(
 	uint		i;
 
 	void *ctx = alloca(my_md5_context_size());
-        my_md5_init(ctx);
+	my_md5_init(ctx);
 
 	n_fields = table->s->fields;
 
@@ -9670,6 +9935,7 @@ wsrep_calc_row_hash(
 	return(0);
 }
 #endif /* WITH_WSREP */
+
 /*
 Updates a row given as a parameter to a new value. Note that we are given
 whole rows, not just the fields which are updated: this incurs some
@@ -9705,11 +9971,11 @@ ha_innobase::update_row(
 	if (m_upd_buf == NULL) {
 		ut_ad(m_upd_buf_size == 0);
 
-                /* Create a buffer for packing the fields of a record. Why
-                  table->stored_rec_length did not work here? Obviously,
-                  because char fields when packed actually became 1 byte
-                  longer, when we also stored the string length as the first
-                  byte. */
+		/* Create a buffer for packing the fields of a record. Why
+		table->stored_rec_length did not work here? Obviously,
+		because char fields when packed actually became 1 byte
+		longer, when we also stored the string length as the first
+		byte. */
 
 		m_upd_buf_size = table->s->stored_rec_length + table->s->max_key_length
 			+ MAX_REF_PARTS * 3;
@@ -9750,7 +10016,10 @@ ha_innobase::update_row(
 	if (!dict_table_is_intrinsic(m_prebuilt->table)
 	    && TrxInInnoDB::is_aborted(trx)) {
 
-		DBUG_RETURN(innobase_rollback(ht, m_user_thd, false));
+		innobase_rollback(ht, m_user_thd, false);
+
+		DBUG_RETURN(convert_error_code_to_mysql(
+			DB_FORCED_ABORT, 0, m_user_thd));
 	}
 
 	/* This is not a delete */
@@ -9830,8 +10099,7 @@ ha_innobase::update_row(
 	if (error == DB_SUCCESS                            &&
 	    wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE &&
 	    wsrep_on(m_user_thd)                           &&
-	    !wsrep_thd_ignore_table(m_user_thd))
-        {
+	    !wsrep_thd_ignore_table(m_user_thd)) {
 		DBUG_PRINT("wsrep", ("update row key"));
 
 		if (wsrep_append_keys(m_user_thd, false, old_row, new_row)) {
@@ -9866,7 +10134,10 @@ ha_innobase::delete_row(
 	if (!dict_table_is_intrinsic(m_prebuilt->table)
 	    && trx_in_innodb.is_aborted()) {
 
-		DBUG_RETURN(innobase_rollback(ht, m_user_thd, false));
+		innobase_rollback(ht, m_user_thd, false);
+
+		DBUG_RETURN(convert_error_code_to_mysql(
+			DB_FORCED_ABORT, 0, m_user_thd));
 	}
 
 	ut_a(m_prebuilt->trx == trx);
@@ -9901,10 +10172,9 @@ ha_innobase::delete_row(
 
 #ifdef WITH_WSREP
 	if (error == DB_SUCCESS                            &&
-            wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE &&
-            wsrep_on(m_user_thd)                           &&
-            !wsrep_thd_ignore_table(m_user_thd))
-        {
+	    wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE &&
+	    wsrep_on(m_user_thd)                           &&
+	    !wsrep_thd_ignore_table(m_user_thd)) {
 		if (wsrep_append_keys(m_user_thd, false, record, NULL)) {
 			DBUG_PRINT("wsrep", ("delete fail"));
 			error = (dberr_t) HA_ERR_INTERNAL_ERROR;
@@ -10106,8 +10376,8 @@ convert_search_mode_to_innobase(
 		return(PAGE_CUR_MBR_EQUAL);
 	case HA_READ_PREFIX:
 		return(PAGE_CUR_UNSUPP);
-		/* JAN: TODO: MySQL 5.7
-        case HA_READ_INVALID:
+	/* JAN: TODO: MySQL 5.7
+	case HA_READ_INVALID:
 		return(PAGE_CUR_UNSUPP);
 		*/
 	/* do not use "default:" in order to produce a gcc warning:
@@ -10275,8 +10545,10 @@ ha_innobase::index_read(
 
 			if (TrxInInnoDB::is_aborted(m_prebuilt->trx)) {
 
-				DBUG_RETURN(innobase_rollback(
-						ht, m_user_thd, false));
+				innobase_rollback(ht, m_user_thd, false);
+
+				DBUG_RETURN(convert_error_code_to_mysql(
+					DB_FORCED_ABORT, 0, m_user_thd));
 			}
 
 			m_prebuilt->ins_sel_stmt = thd_is_ins_sel_stmt(
@@ -10430,7 +10702,8 @@ ha_innobase::innobase_get_index(
 						  " index translation table",
 						  key ? key->name : "NULL",
 						  keynr,
-						  m_prebuilt->table->name.m_name);
+						  m_prebuilt->table->name
+						  .m_name);
 			}
 
 			index = dict_table_get_index_on_name(
@@ -10473,7 +10746,10 @@ ha_innobase::change_active_index(
 	if (!dict_table_is_intrinsic(m_prebuilt->table)
 	    && trx_in_innodb.is_aborted()) {
 
-		DBUG_RETURN(innobase_rollback(ht, m_user_thd, false));
+		innobase_rollback(ht, m_user_thd, false);
+
+		DBUG_RETURN(convert_error_code_to_mysql(
+			DB_FORCED_ABORT, 0,  m_user_thd));
 	}
 
 	active_index = keynr;
@@ -10527,7 +10803,7 @@ ha_innobase::change_active_index(
 		/* The caller seems to ignore this.  Thus, we must check
 		this again in row_search_for_mysql(). */
 		DBUG_RETURN(convert_error_code_to_mysql(DB_MISSING_HISTORY,
-                                                        0, NULL));
+				0, NULL));
 	}
 
 	ut_a(m_prebuilt->search_tuple != 0);
@@ -10536,14 +10812,14 @@ ha_innobase::change_active_index(
 	since FT search returns rank only. In addition engine should
 	be able to retrieve FTS_DOC_ID column value if necessary. */
 	if ((m_prebuilt->index->type & DICT_FTS)) {
-		/* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_STORE_FTS_DOC_ID
 		if (table->fts_doc_id_field
 		    && bitmap_is_set(table->read_set,
 				     table->fts_doc_id_field->field_index
 				     && m_prebuilt->read_just_key)) {
 			m_prebuilt->fts_doc_id_in_read_set = 1;
 		}
-		*/
+#endif
 	} else {
 		dtuple_set_n_fields(m_prebuilt->search_tuple,
 				    m_prebuilt->index->n_fields);
@@ -10554,11 +10830,13 @@ ha_innobase::change_active_index(
 
 		/* If it's FTS query and FTS_DOC_ID exists FTS_DOC_ID field is
 		always added to read_set. */
-		/* JAN: TODO: MySQL 5.7
+
+#ifdef MYSQL_STORE_FTS_DOC_ID
 		m_prebuilt->fts_doc_id_in_read_set =
 			(m_prebuilt->read_just_key && table->fts_doc_id_field
 			 && m_prebuilt->in_fts_query);
-		*/
+#endif
+
 	}
 
 	/* MySQL changes the active index for a handle also during some
@@ -10589,6 +10867,7 @@ ha_innobase::general_fetch(
 	DBUG_ENTER("general_fetch");
 
 	const trx_t*	trx = m_prebuilt->trx;
+	dberr_t	ret;
 
 	ut_ad(trx == thd_to_trx(m_user_thd));
 
@@ -10596,17 +10875,20 @@ ha_innobase::general_fetch(
 
 	if (!intrinsic && TrxInInnoDB::is_aborted(trx)) {
 
-		DBUG_RETURN(innobase_rollback(ht, m_user_thd, false));
+		innobase_rollback(ht, m_user_thd, false);
+
+		DBUG_RETURN(convert_error_code_to_mysql(
+			DB_FORCED_ABORT, 0,  m_user_thd));
 	}
 
 	innobase_srv_conc_enter_innodb(m_prebuilt);
 
-	dberr_t	ret;
-
 	if (!intrinsic) {
+
 		ret = row_search_mvcc(
 			buf, PAGE_CUR_UNSUPP, m_prebuilt, match_mode,
 			direction);
+
 	} else {
 		ret = row_search_no_mvcc(
 			buf, PAGE_CUR_UNSUPP, m_prebuilt, match_mode,
@@ -10654,9 +10936,7 @@ ha_innobase::general_fetch(
 			table->s->table_name.str);
 
 		table->status = STATUS_NOT_FOUND;
-		error = HA_ERR_NO_SUCH_TABLE;
-		// JAN: TODO: MySQL 5.7
-		//error = HA_ERR_TABLESPACE_MISSING;
+		error = HA_ERR_TABLESPACE_MISSING;
 		break;
 	default:
 		error = convert_error_code_to_mysql(
@@ -10963,9 +11243,13 @@ ha_innobase::ft_init_ext(
 
 	if (trx_in_innodb.is_aborted()) {
 
-		int	ret = innobase_rollback(ht, m_user_thd, false);
+		innobase_rollback(ht, m_user_thd, false);
 
-		my_error(ret, MYF(0));
+		int	err;
+		err = convert_error_code_to_mysql(
+			DB_FORCED_ABORT, 0, m_user_thd);
+
+		my_error(err, MYF(0));
 
 		return(NULL);
 	}
@@ -11016,7 +11300,8 @@ ha_innobase::ft_init_ext(
 	const byte*	q = reinterpret_cast<const byte*>(
 		const_cast<char*>(query));
 
-	dberr_t	error = fts_query(trx, index, flags, q, query_len, &result);
+	dberr_t	error = fts_query(trx, index, flags, q, query_len, &result,
+				  m_prebuilt->m_fts_limit);
 
 	if (error != DB_SUCCESS) {
 		my_error(convert_error_code_to_mysql(error, 0, NULL), MYF(0));
@@ -11050,13 +11335,14 @@ ha_innobase::ft_init_ext_with_hints(
 /*================================*/
 	uint			keynr,		/* in: key num */
 	String*			key,		/* in: key */
-	void*		hints)		/* in: hints  */
-// JAN: TODO: MySQL 5.7
-//	Ft_hints*		hints)		/* in: hints  */
+	void*			hints)		/* in: hints  */
 {
 	/* TODO Implement function properly working with FT hint. */
-	//return(ft_init_ext(hints->get_flags(), keynr, key));
+#ifdef MYSQL_FT_INIT_EXT
+	return(ft_init_ext(hints->get_flags(), keynr, key));
+#else
 	return NULL;
+#endif
 }
 
 /*****************************************************************//**
@@ -11116,7 +11402,10 @@ ha_innobase::ft_read(
 
 	if (trx_in_innodb.is_aborted()) {
 
-		return(innobase_rollback(ht, m_user_thd, false));
+		innobase_rollback(ht, m_user_thd, false);
+
+		return(convert_error_code_to_mysql(
+			DB_FORCED_ABORT, 0, m_user_thd));
 	}
 
 	row_prebuilt_t*	ft_prebuilt;
@@ -11158,6 +11447,7 @@ ha_innobase::ft_read(
 		/* If we only need information from result we can return
 		   without fetching the table row */
 		if (ft_prebuilt->read_just_key) {
+#ifdef MYSQL_STORE_FTS_DOC_ID
 			if (m_prebuilt->fts_doc_id_in_read_set) {
 				fts_ranking_t* ranking;
 				ranking = rbt_value(fts_ranking_t,
@@ -11165,6 +11455,7 @@ ha_innobase::ft_read(
 				innobase_fts_store_docid(
 					table, ranking->doc_id);
 			}
+#endif
 			table->status= 0;
 			return(0);
 		}
@@ -11241,9 +11532,7 @@ ha_innobase::ft_read(
 				table->s->table_name.str);
 
 			table->status = STATUS_NOT_FOUND;
-			error = HA_ERR_NO_SUCH_TABLE;
-			// JAN: TODO: MySQL 5.7
-			// error = HA_ERR_TABLESPACE_MISSING;
+			error = HA_ERR_TABLESPACE_MISSING;
 			break;
 		default:
 			error = convert_error_code_to_mysql(
@@ -11391,8 +11680,10 @@ wsrep_append_foreign_key(
 		WSREP_ERROR(
 			"FK key set failed: %lu (%lu %lu), index: %s %s, %s",
 			rcode, referenced, shared,
-			(index) ? index->name() : "void index",
-			(index) ? index->table->name.m_name : "void table",
+			(index && index->name)       ? index->name :
+				"void index",
+			(index && index->table_name) ? index->table_name :
+				"void table",
 			wsrep_thd_query(thd));
 		return DB_ERROR;
 	}
@@ -11802,6 +12093,7 @@ create_table_check_doc_id_col(
 	return(false);
 }
 
+#ifdef MYSQL_VIRTUAL_COLUMNS
 /** Set up base columns for virtual column
 @param[in]	table		InnoDB table
 @param[in]	field		MySQL field
@@ -11812,9 +12104,10 @@ innodb_base_col_setup(
 	const Field*	field,
 	dict_v_col_t*	v_col)
 {
+	int     n = 0;
+
 	for (uint i= 0; i < field->table->s->fields; ++i) {
-		// const Field* base_field = field->table->field[i];
-		/* JAN: TODO: MySQL 5.7 Virtual columns
+		const Field* base_field = field->table->field[i];
 		if (!base_field->is_virtual_gcol()
 			&& bitmap_is_set(&field->gcol_info->base_columns_map, i)) {
 			ulint   z;
@@ -11833,19 +12126,62 @@ innodb_base_col_setup(
 			ut_ad(v_col->base_col[n]->ind == z);
 			n++;
 		}
-		*/
 	}
 }
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
+#ifdef MYSQL_BASE_COLUMN
+/** Set up base columns for stored column
+ at param[in]	table	InnoDB table
+ at param[in]	field	MySQL field
+ at param[in,out]	s_col	stored column */
+void
+innodb_base_col_setup_for_stored(
+	const dict_table_t*	table,
+	const Field*		field,
+	dict_s_col_t*		s_col)
+{
+	ulint	n = 0;
+
+	for (uint i= 0; i < field->table->s->fields; ++i) {
+		const Field* base_field = field->table->field[i];
+
+		if (!innobase_is_s_fld(base_field)
+		    && !innobase_is_v_fld(base_field)
+		    && bitmap_is_set(&field->gcol_info->base_columns_map,
+				     i)) {
+			ulint	z;
+			for (z = 0; z < table->n_cols; z++) {
+				const char* name = dict_table_get_col_name(
+						table, z);
+				if (!innobase_strcasecmp(
+					name, base_field->field_name)) {
+					break;
+				}
+			}
+
+			ut_ad(z != table->n_cols);
+
+			s_col->base_col[n] = dict_table_get_nth_col(table, z);
+			n++;
+
+			if (n == s_col->num_base) {
+				break;
+			}
+		}
+	}
+}
+#endif
 
 /** Create a table definition to an InnoDB database.
 @return ER_* level error */
-inline __attribute__((warn_unused_result))
+inline MY_ATTRIBUTE((warn_unused_result))
 int
 create_table_info_t::create_table_def()
 {
 	dict_table_t*	table;
 	ulint		n_cols;
-	dberr_t		err;
+	ulint		s_cols;
 	ulint		col_type;
 	ulint		col_len;
 	ulint		nulls_allowed;
@@ -11862,6 +12198,7 @@ create_table_info_t::create_table_def()
 	ulint		space_id = 0;
 	ulint		actual_n_cols;
 	ha_table_option_struct *options= m_form->s->option_struct;
+	dberr_t		err = DB_SUCCESS;
 
 	DBUG_ENTER("create_table_def");
 	DBUG_PRINT("enter", ("table_name: %s", m_table_name));
@@ -11890,7 +12227,9 @@ create_table_info_t::create_table_def()
 	}
 
 	n_cols = m_form->s->fields;
+	s_cols = m_form->s->stored_fields;
 
+#ifdef MYSQL_VIRTUAL_COLUMNS
 	/* Find out any virtual column */
 	for (i = 0; i < n_cols; i++) {
 		Field*	field = m_form->field[i];
@@ -11899,13 +12238,15 @@ create_table_info_t::create_table_def()
 			num_v++;
 		}
 	}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
+	ut_ad(trx_state_eq(m_trx, TRX_STATE_NOT_STARTED));
 
 	/* Check whether there already exists a FTS_DOC_ID column */
 	if (create_table_check_doc_id_col(m_trx, m_form, &doc_id_col)){
 
 		/* Raise error if the Doc ID column is of wrong type or name */
 		if (doc_id_col == ULINT_UNDEFINED) {
-			trx_commit_for_mysql(m_trx);
 
 			err = DB_ERROR;
 			goto error_ret;
@@ -11935,7 +12276,7 @@ create_table_info_t::create_table_def()
 	/* Set the hidden doc_id column. */
 	if (m_flags2 & DICT_TF2_FTS) {
 		table->fts->doc_col = has_doc_id_col
-				      ? doc_id_col : n_cols - num_v;
+				      ? doc_id_col : s_cols;
 	}
 
 	if (strlen(m_temp_path) != 0) {
@@ -11964,9 +12305,10 @@ create_table_info_t::create_table_def()
 
 	for (i = 0; i < n_cols; i++) {
 		ulint	is_virtual;
+		bool	is_stored MY_ATTRIBUTE((unused));
 		Field*	field = m_form->field[i];
 
-                if (!field->stored_in_db()) {
+		if (!field->stored_in_db()) {
 			continue;
 		}
 
@@ -12014,6 +12356,10 @@ create_table_info_t::create_table_def()
 
 			charset_no = (ulint) field->charset()->number;
 
+			DBUG_EXECUTE_IF("simulate_max_char_col",
+					charset_no = MAX_CHAR_COLL_NUM + 1;
+					);
+
 			if (charset_no > MAX_CHAR_COLL_NUM) {
 				/* in data0type.h we assume that the
 				number fits in one byte in prtype */
@@ -12025,6 +12371,11 @@ create_table_info_t::create_table_def()
 					" Unsupported code %lu.",
 					(ulong) charset_no);
 				mem_heap_free(heap);
+				dict_mem_table_free(table);
+
+				ut_ad(trx_state_eq(
+					m_trx, TRX_STATE_NOT_STARTED));
+
 				DBUG_RETURN(ER_CANT_CREATE_TABLE);
 			}
 		}
@@ -12051,6 +12402,7 @@ create_table_info_t::create_table_def()
 		}
 
 		is_virtual = (innobase_is_v_fld(field)) ? DATA_VIRTUAL : 0;
+		is_stored = innobase_is_s_fld(field);
 
 		/* First check whether the column to be added has a
 		system reserved name. */
@@ -12060,7 +12412,7 @@ create_table_info_t::create_table_def()
 err_col:
 			dict_mem_table_free(table);
 			mem_heap_free(heap);
-			trx_commit_for_mysql(m_trx);
+			ut_ad(trx_state_eq(m_trx, TRX_STATE_NOT_STARTED));
 
 			err = DB_ERROR;
 			goto error_ret;
@@ -12076,6 +12428,7 @@ create_table_info_t::create_table_def()
 					charset_no),
 				col_len);
 		} else {
+#ifdef MYSQL_VIRTUAL_COLUMNS
 			dict_mem_table_add_v_col(table, heap,
 				field_name, col_type,
 				dtype_form_prtype(
@@ -12086,11 +12439,22 @@ create_table_info_t::create_table_def()
 					charset_no),
 				col_len, i,
 				0);
-				// JAN: TODO: MySQL 5.7 Virtual columns
-				//field->gcol_info->non_virtual_base_columns());
-		}
+
+				field->gcol_info->non_virtual_base_columns());
+#endif
 	}
 
+#ifdef MYSQL_STORED_BASE_COLUMNS
+		if (is_stored) {
+			ut_ad(!is_virtual);
+			/* Added stored column in m_s_cols list. */
+			dict_mem_table_add_s_col(
+				table,
+				field->gcol_info->non_virtual_base_columns());
+		}
+#endif
+	}
+#ifdef MYSQL_VIRTUAL_COLUMNS
 	if (num_v) {
 		for (i = 0; i < n_cols; i++) {
 			dict_v_col_t*	v_col;
@@ -12109,22 +12473,46 @@ create_table_info_t::create_table_def()
 		}
 	}
 
+	/** Fill base columns for the stored column present in the list. */
+	if (table->s_cols && table->s_cols->size()) {
+
+		for (i = 0; i < n_cols; i++) {
+			Field*  field = m_form->field[i];
+
+			if (!innobase_is_s_fld(field)) {
+				continue;
+			}
+
+			dict_s_col_list::iterator       it;
+			for (it = table->s_cols->begin();
+			     it != table->s_cols->end(); ++it) {
+				dict_s_col_t	s_col = *it;
+
+				if (s_col.s_pos == i) {
+					innodb_base_col_setup_for_stored(
+						table, field, &s_col);
+					break;
+				}
+			}
+		}
+	}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
 	/* Add the FTS doc_id hidden column. */
 	if (m_flags2 & DICT_TF2_FTS && !has_doc_id_col) {
 		fts_add_doc_id_column(table, heap);
 	}
 
+	ut_ad(trx_state_eq(m_trx, TRX_STATE_NOT_STARTED));
+
 	/* If temp table, then we avoid creation of entries in SYSTEM TABLES.
 	Given that temp table lifetime is limited to connection/server lifetime
 	on re-start we don't need to restore temp-table and so no entry is
 	needed in SYSTEM tables. */
 	if (dict_table_is_temporary(table)) {
-		ulint clen = 0;
-
-		// JAN: TODO: MySQL 5.7 compressed tables
-		//		if (m_create_info->compress.length > 0) {
 
-		if (clen > 0) {
+#ifdef MYSQL_COMPRESSION
+		if (m_create_info->compress.length > 0) {
 			push_warning_printf(
 				m_thd,
 				Sql_condition::WARN_LEVEL_WARN,
@@ -12134,8 +12522,17 @@ create_table_info_t::create_table_def()
 
 			err = DB_UNSUPPORTED;
 
-		} else {
+			dict_mem_table_free(table);
+		} else if (m_create_info->encrypt_type.length > 0
+			   && !Encryption::is_none(
+				   m_create_info->encrypt_type.str)) {
 
+			my_error(ER_TABLESPACE_CANNOT_ENCRYPT, MYF(0));
+			err = DB_UNSUPPORTED;
+			dict_mem_table_free(table);
+			*/
+		} else {
+#endif /* MYSQL_COMPRESSION */
 			/* Get a new table ID */
 			dict_table_assign_new_id(table, m_trx);
 
@@ -12167,22 +12564,18 @@ create_table_info_t::create_table_def()
 
 				mem_heap_free(temp_table_heap);
 			}
+#ifdef MYSQL_COMPRESSION
 		}
+#endif
 
 	} else {
+		const char*     algorithm = NULL;
 
-                const char*     algorithm = "";
-		// JAN: TODO: MySQL 5.7
-		//                const char*     algorithm = m_create_info->compress.str;
-
-		err = DB_SUCCESS;
-		ulint clen = 0;
+#if MYSQL_COMPRESSION_ENCRYPTION
+		const char*     algorithm = m_create_info->compress.str;
 
-		//		if (!(m_flags2 & DICT_TF2_USE_FILE_PER_TABLE)
-		//    && m_create_info->compress.length > 0
-		//    && !Compression::is_none(algorithm)) {
 		if (!(m_flags2 & DICT_TF2_USE_FILE_PER_TABLE)
-		    && clen > 0
+		    && m_create_info->compress.length > 0
 		    && !Compression::is_none(algorithm)) {
 
 			push_warning_printf(
@@ -12195,24 +12588,60 @@ create_table_info_t::create_table_def()
 			algorithm = NULL;
 
 			err = DB_UNSUPPORTED;
+			dict_mem_table_free(table);
 
 		} else if (Compression::validate(algorithm) != DB_SUCCESS
 			   || m_form->s->row_type == ROW_TYPE_COMPRESSED
 			   || m_create_info->key_block_size > 0) {
 
 			algorithm = NULL;
-                }
+		}
+
+		const char*	encrypt = m_create_info->encrypt_type.str;
+
+		if (!(m_flags2 & DICT_TF2_USE_FILE_PER_TABLE)
+		    && m_create_info->encrypt_type.length > 0
+		    && !Encryption::is_none(encrypt)) {
+
+			my_error(ER_TABLESPACE_CANNOT_ENCRYPT, MYF(0));
+			err = DB_UNSUPPORTED;
+			dict_mem_table_free(table);
+
+		} else if (!Encryption::is_none(encrypt)) {
+			/* Set the encryption flag. */
+			byte*			master_key = NULL;
+			ulint			master_key_id;
+			Encryption::Version	version;
+
+			/* Check if keyring is ready. */
+			Encryption::get_master_key(&master_key_id,
+						   &master_key,
+						   &version);
+
+			if (master_key == NULL) {
+				my_error(ER_CANNOT_FIND_KEY_IN_KEYRING,
+					 MYF(0));
+				err = DB_UNSUPPORTED;
+				dict_mem_table_free(table);
+			} else {
+				my_free(master_key);
+				DICT_TF2_FLAG_SET(table,
+						  DICT_TF2_ENCRYPTION);
+			}
+		}
+#endif /* MYSQL_COMPRESSION_ENCRYPTION */
 
 		if (err == DB_SUCCESS) {
 			err = row_create_table_for_mysql(
 				table, algorithm, m_trx, false,
 				(fil_encryption_t)options->encryption,
 				options->encryption_key_id);
+
 		}
 
 		if (err == DB_IO_NO_PUNCH_HOLE_FS) {
 
-			ut_ad(!is_shared_tablespace(table->space));
+			ut_ad(!dict_table_in_shared_tablespace(table));
 
 			push_warning_printf(
 				m_thd,
@@ -12224,6 +12653,9 @@ create_table_info_t::create_table_def()
 
 			err = DB_SUCCESS;
 		}
+
+		DBUG_EXECUTE_IF("ib_crash_during_create_for_encryption",
+				DBUG_SUICIDE(););
 	}
 
 	mem_heap_free(heap);
@@ -12328,6 +12760,7 @@ create_index(
 		key->user_defined_key_parts * sizeof *
 				field_lengths, MYF(MY_FAE));
 	*/
+
 	field_lengths = (ulint*) my_malloc(
 		key->user_defined_key_parts * sizeof *
 				field_lengths, MYF(MY_FAE));
@@ -12628,7 +13061,9 @@ validate_tablespace_name(
 bool
 create_table_info_t::create_option_tablespace_is_valid()
 {
-	ut_ad(m_use_shared_space);
+	if (!m_use_shared_space) {
+		return(true);
+	}
 
 	if (0 != validate_tablespace_name(m_create_info->tablespace, true)) {
 		return(false);
@@ -12747,20 +13182,91 @@ create_table_info_t::create_option_tablespace_is_valid()
 	return(true);
 }
 
-/** Validate the create options. Check that the options KEY_BLOCK_SIZE,
-ROW_FORMAT, DATA DIRECTORY, TEMPORARY & TABLESPACE are compatible with
-each other and other settings.  These CREATE OPTIONS are not validated
-here unless innodb_strict_mode is on. With strict mode, this function
-will report each problem it finds using a custom message with error
-code ER_ILLEGAL_HA_CREATE_OPTION, not its built-in message.
- at return NULL if valid, string name of bad option if not. */
-const char*
-create_table_info_t::create_options_are_invalid()
+#ifdef MYSQL_COMPRESSION
+/** Validate the COPMRESSION option.
+ at return true if valid, false if not. */
+bool
+create_table_info_t::create_option_compression_is_valid()
 {
-	bool	has_key_block_size = (m_create_info->key_block_size != 0);
+	dberr_t		err;
+	Compression	compression;
 
-	const char*	ret = NULL;
-	enum row_type	row_format	= m_create_info->row_type;
+	if (m_create_info->compress.length == 0) {
+		return(true);
+	}
+
+	err = Compression::check(m_create_info->compress.str, &compression);
+
+	if (err == DB_UNSUPPORTED) {
+		push_warning_printf(
+			m_thd,
+			Sql_condition::WARN_LEVEL_WARN,
+			ER_UNSUPPORTED_EXTENSION,
+			"InnoDB: Unsupported compression algorithm '%s'",
+			m_create_info->compress.str);
+		return(false);
+	}
+
+	/* Allow Compression=NONE on any tablespace or row format. */
+	if (compression.m_type == Compression::NONE) {
+		return(true);
+	}
+
+	static char intro[] = "InnoDB: Page Compression is not supported";
+
+	if (m_create_info->key_block_size != 0
+	    || m_create_info->row_type == ROW_TYPE_COMPRESSED) {
+		push_warning_printf(
+			m_thd, Sql_condition::WARN_LEVEL_WARN,
+			ER_UNSUPPORTED_EXTENSION,
+			"%s with row_format=compressed or"
+			" key_block_size > 0", intro);
+		return(false);
+	}
+
+	if (m_create_info->options & HA_LEX_CREATE_TMP_TABLE) {
+		push_warning_printf(
+			m_thd, Sql_condition::WARN_LEVEL_WARN,
+			HA_ERR_UNSUPPORTED,
+			"%s for temporary tables", intro);
+		return(false);
+	}
+
+	if (tablespace_is_general_space(m_create_info)) {
+		push_warning_printf(
+			m_thd, Sql_condition::WARN_LEVEL_WARN,
+			HA_ERR_UNSUPPORTED,
+			"%s for shared general tablespaces", intro);
+		return(false);
+	}
+
+	/* The only non-file-per-table tablespace left is the system space. */
+	if (!m_use_file_per_table) {
+		push_warning_printf(
+			m_thd, Sql_condition::WARN_LEVEL_WARN,
+			HA_ERR_UNSUPPORTED,
+			"%s for the system tablespace", intro);
+		return(false);
+	}
+
+	return(true);
+}
+#endif /* MYSQL_COMPRESSION */
+
+/** Validate the create options. Check that the options KEY_BLOCK_SIZE,
+ROW_FORMAT, DATA DIRECTORY, TEMPORARY & TABLESPACE are compatible with
+each other and other settings.  These CREATE OPTIONS are not validated
+here unless innodb_strict_mode is on. With strict mode, this function
+will report each problem it finds using a custom message with error
+code ER_ILLEGAL_HA_CREATE_OPTION, not its built-in message.
+ at return NULL if valid, string name of bad option if not. */
+const char*
+create_table_info_t::create_options_are_invalid()
+{
+	bool	has_key_block_size = (m_create_info->key_block_size != 0);
+
+	const char*	ret = NULL;
+	enum row_type	row_format	= m_create_info->row_type;
 
 	ut_ad(m_thd != NULL);
 	ut_ad(m_create_info != NULL);
@@ -12769,17 +13275,18 @@ create_table_info_t::create_options_are_invalid()
 	non-strict-mode.  If it is incorrect or is incompatible with other
 	options, then we will return an error. Make sure the tablespace exists
 	and is compatible with this table */
-	if (m_use_shared_space
-	    && !create_option_tablespace_is_valid()) {
+	if (!create_option_tablespace_is_valid()) {
 		return("TABLESPACE");
 	}
 
-	/* If innodb_strict_mode is not set don't do any more validation. */
+	/* If innodb_strict_mode is not set don't do any more validation.
+	Also, if this table is being put into a shared general tablespace
+	we ALWAYS act like strict mode is ON. */
 	if (!m_use_shared_space && !(THDVAR(m_thd, strict_mode))) {
 		return(NULL);
 	}
 
-	/* First check if a non-zero KEY_BLOCK_SIZE was specified. */
+	/* Check if a non-zero KEY_BLOCK_SIZE was specified. */
 	if (has_key_block_size) {
 		switch (m_create_info->key_block_size) {
 			ulint	kbs_max;
@@ -12943,44 +13450,24 @@ create_table_info_t::create_options_are_invalid()
 		}
 	}
 
-#ifdef MYSQL_COMPRESSION
-	/* Note: Currently the max length is 4: ZLIB, LZ4, NONE. */
-
-	if (ret == NULL && m_create_info->compress.length > 0) {
+#ifdef MYSQL_COMPRESSION_ENCRYPTION
+	/* Validate the page compression parameter. */
+	if (!create_option_compression_is_valid()) {
+		return("COMPRESSION");
+	}
 
+	/* Check the encryption option. */
+	if (ret == NULL && m_create_info->encrypt_type.length > 0) {
 		dberr_t		err;
-		Compression	compression;
 
-		err = Compression::check(
-			m_create_info->compress.str, &compression);
+		err = Encryption::validate(m_create_info->encrypt_type.str);
 
 		if (err == DB_UNSUPPORTED) {
-
-			push_warning_printf(
-				m_thd,
-				Sql_condition::WARN_LEVEL_WARN,
-				ER_UNSUPPORTED_EXTENSION,
-				"InnoDB: Unsupported compression algorithm '"
-				"%s'",
-				m_create_info->compress.str);
-
-			ret = "COMPRESSION";
-
-		} else if (m_create_info->key_block_size > 0
-			   && compression.m_type != Compression::NONE) {
-
-			push_warning_printf(
-				m_thd,
-				Sql_condition::WARN_LEVEL_WARN,
-				ER_UNSUPPORTED_EXTENSION,
-				"InnODB: Attribute not supported with row "
-				"format compressed or key block size > 0");
-
-			ret = "COMPRESSION";
+			my_error(ER_INVALID_ENCRYPTION_OPTION, MYF(0));
+			ret = "ENCRYPTION";
 		}
-
 	}
-#endif /* MYSQL_COMPRESSION */
+#endif
 
 	return(ret);
 }
@@ -12988,7 +13475,6 @@ create_table_info_t::create_options_are_invalid()
 /*****************************************************************//**
 Check engine specific table options not handled by SQL-parser.
 @return	NULL if valid, string if not */
-UNIV_INTERN
 const char*
 create_table_info_t::check_table_options()
 {
@@ -13005,7 +13491,7 @@ create_table_info_t::check_table_options()
 		return "ENCRYPTED";
  	}
 
-        if (encrypt == FIL_SPACE_ENCRYPTION_OFF && srv_encrypt_tables == 2) {
+	if (encrypt == FIL_SPACE_ENCRYPTION_OFF && srv_encrypt_tables == 2) {
 		push_warning(
 			m_thd, Sql_condition::WARN_LEVEL_WARN,
 			HA_WRONG_CREATE_OPTION,
@@ -13087,7 +13573,7 @@ create_table_info_t::check_table_options()
 
 	/* If encryption is set up make sure that used key_id is found */
 	if (encrypt == FIL_SPACE_ENCRYPTION_ON ||
-            (encrypt == FIL_SPACE_ENCRYPTION_DEFAULT && srv_encrypt_tables)) {
+		(encrypt == FIL_SPACE_ENCRYPTION_DEFAULT && srv_encrypt_tables)) {
 		if (!encryption_key_id_exists((unsigned int)options->encryption_key_id)) {
 			push_warning_printf(
 				m_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -13312,6 +13798,40 @@ create_table_info_t::innobase_table_flags()
 	m_flags = 0;
 	m_flags2 = 0;
 
+#ifdef MYSQL_COMPRESSION
+	/* Validate the page compression parameter. */
+	if (!create_option_compression_is_valid()) {
+		/* No need to do anything. Warnings were issued.
+		The compresion setting will be ignored later.
+		If inodb_strict_mode=ON, this is called twice unless
+		there was a problem before.
+		If inodb_strict_mode=OFF, this is the only call. */
+	}
+#endif
+
+#ifdef MYSQL_ENCRYPTION
+	/* Validate the page encryption parameter. */
+	if (m_create_info->encrypt_type.length > 0) {
+
+		const char* encryption = m_create_info->encrypt_type.str;
+
+		if (Encryption::validate(encryption) != DB_SUCCESS) {
+			/* Incorrect encryption option */
+			my_error(ER_INVALID_ENCRYPTION_OPTION, MYF(0));
+			DBUG_RETURN(false);
+		}
+
+		if (m_use_shared_space
+		    || (m_create_info->options & HA_LEX_CREATE_TMP_TABLE)) {
+			if (!Encryption::is_none(encryption)) {
+				/* Can't encrypt shared tablespace */
+				my_error(ER_TABLESPACE_CANNOT_ENCRYPT, MYF(0));
+				DBUG_RETURN(false);
+			}
+		}
+	}
+#endif /* MYSQL_ENCRYPTION */
+
 	/* Check if there are any FTS indexes defined on this table. */
 	for (uint i = 0; i < m_form->s->keys; i++) {
 		const KEY*	key = &m_form->key_info[i];
@@ -13327,11 +13847,6 @@ create_table_info_t::innobase_table_flags()
 				DBUG_RETURN(false);
 			}
 
-			if (key->flags & HA_USES_PARSER) {
-				my_error(ER_INNODB_NO_FT_USES_PARSER, MYF(0));
-                                DBUG_RETURN(false);
-			}
-
 			if (fts_doc_id_index_bad) {
 				goto index_bad;
 			}
@@ -13368,7 +13883,6 @@ create_table_info_t::innobase_table_flags()
 	}
 
 	//rec_format_t row_format = m_form->s->row_type;
-	ulint clen = 0;
 
 	if (m_create_info->key_block_size > 0) {
 		/* The requested compressed page size (key_block_size)
@@ -13414,35 +13928,6 @@ create_table_info_t::innobase_table_flags()
 				"InnoDB: ignoring KEY_BLOCK_SIZE=%lu.",
 				m_create_info->key_block_size);
 		}
-
-	} else if (clen > 0) {
-		// JAN: TODO: MySQL 5.7
-		//} else if (m_create_info->compress.length > 0) {
-
-		if (m_use_shared_space
-		    || (m_create_info->options & HA_LEX_CREATE_TMP_TABLE)) {
-
-			push_warning_printf(
-				m_thd,
-				Sql_condition::WARN_LEVEL_WARN,
-				HA_ERR_UNSUPPORTED,
-				"InnoDB: Cannot compress pages of shared "
-				"tablespaces");
-		}
-
-		//const char*     compression = m_create_info->compress.str;
-		const char*     compression = "";
-
-		if (Compression::validate(compression) != DB_SUCCESS) {
-
-			push_warning_printf(
-				m_thd,
-				Sql_condition::WARN_LEVEL_WARN,
-				HA_ERR_UNSUPPORTED,
-				"InnoDB: Unsupported compression "
-				"algorithm '%s'",
-				compression);
-		}
 	}
 
 	row_type = m_form->s->row_type;
@@ -13507,15 +13992,15 @@ create_table_info_t::innobase_table_flags()
 
 		} else {
 			switch(row_type) {
-			  case ROW_TYPE_COMPRESSED:
-			    innodb_row_format = REC_FORMAT_COMPRESSED;
-			    break;
-			  case ROW_TYPE_DYNAMIC:
-			    innodb_row_format = REC_FORMAT_DYNAMIC;
-                            break;
-			  default:
-			    /* Not possible, avoid compiler warning */
-			    break;
+			case ROW_TYPE_COMPRESSED:
+				innodb_row_format = REC_FORMAT_COMPRESSED;
+				break;
+			case ROW_TYPE_DYNAMIC:
+				innodb_row_format = REC_FORMAT_DYNAMIC;
+				break;
+			default:
+				/* Not possible, avoid compiler warning */
+				break;
 			}
 			break; /* Correct row_format */
 		}
@@ -13554,19 +14039,20 @@ create_table_info_t::innobase_table_flags()
 		m_flags2 |= DICT_TF2_TEMPORARY;
 		/* Intrinsic tables reside only in the shared temporary
 		tablespace and we will always use ROW_FORMAT=DYNAMIC. */
-		/* JAN: TODO: MySQL 5.7
+
+#ifdef MYSQL_COMPRESSION
 		if ((m_create_info->options & HA_LEX_CREATE_INTERNAL_TMP_TABLE)
 		    && !m_use_file_per_table) {
-		if (!m_use_file_per_table) {
-		*/
+
 			/* We do not allow compressed instrinsic
 			temporary tables. */
-		/*
+
 			ut_ad(zip_ssize == 0);
 			m_flags2 |= DICT_TF2_INTRINSIC;
 			innodb_row_format = REC_FORMAT_DYNAMIC;
 		}
-		*/
+#endif
+
 	}
 
 	/* Set the table flags */
@@ -13818,8 +14304,6 @@ create_table_info_t::initialize()
 		DBUG_RETURN(HA_ERR_TOO_MANY_FIELDS);
 	}
 
-	ut_ad(m_form->s->row_type == m_create_info->row_type);
-
 	/* Check for name conflicts (with reserved name) for
 	any user indices to be created. */
 	if (innobase_index_name_is_reserved(m_thd, m_form->key_info,
@@ -13827,6 +14311,8 @@ create_table_info_t::initialize()
 		DBUG_RETURN(HA_ERR_WRONG_INDEX);
 	}
 
+	ut_ad(m_form->s->row_type == m_create_info->row_type);
+
 	/* Get the transaction associated with the current thd, or create one
 	if not yet created */
 
@@ -13839,6 +14325,7 @@ create_table_info_t::initialize()
 	DBUG_RETURN(0);
 }
 
+
 /** Prepare to create a new table to an InnoDB database.
 @param[in]	name	Table name
 @return error number */
@@ -13858,7 +14345,7 @@ create_table_info_t::prepare_create_table(
 	normalize_table_name(m_table_name, name);
 
 	/* Validate table options not handled by the SQL-parser */
-	if(check_table_options()) {
+	if (check_table_options()) {
 		DBUG_RETURN(HA_WRONG_CREATE_OPTION);
 	}
 
@@ -13877,9 +14364,7 @@ create_table_info_t::prepare_create_table(
 	}
 
 	if (high_level_read_only && !is_intrinsic_temp_table()) {
-		DBUG_RETURN(HA_ERR_TABLE_READONLY);
-		// JAN: TODO: MySQL 5.7
-		//DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
+		DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
 	}
 
 	DBUG_RETURN(parse_table_name(name));
@@ -13901,14 +14386,14 @@ create_table_info_t::create_table()
 
 	/* Look for a primary key */
 	primary_key_no = (m_form->s->primary_key != MAX_KEY ?
-			  (int) m_form->s->primary_key :
-			  -1);
+			  (int) m_form->s->primary_key : -1);
 
 	/* Our function innobase_get_mysql_key_number_for_index assumes
 	the primary key is always number 0, if it exists */
 	ut_a(primary_key_no == -1 || primary_key_no == 0);
 
 	error = create_table_def();
+
 	if (error) {
 		DBUG_RETURN(error);
 	}
@@ -14058,7 +14543,7 @@ create_table_info_t::create_table()
 				" table where referencing columns appear"
 				" as the first columns.\n", m_table_name);
 			break;
-			/* JAN: TODO: MySQL 5.7 Virtual columns
+#ifdef MYSQL_VIRTUAL_COLUMNS
 		case DB_NO_FK_ON_V_BASE_COL:
 			push_warning_printf(
 				m_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -14070,7 +14555,7 @@ create_table_info_t::create_table()
 				" on columns being part of virtual index.\n",
 				m_table_name);
 			break;
-			*/
+#endif
 		default:
 			break;
 		}
@@ -14112,6 +14597,7 @@ create_table_info_t::create_table_update_dict()
 	innobase_table = thd_to_innodb_session(m_thd)->lookup_table_handler(
 		m_table_name);
 
+
 	if (innobase_table == NULL) {
 		innobase_table = dict_table_open_on_name(
 			m_table_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
@@ -14382,8 +14868,10 @@ ha_innobase::discard_or_import_tablespace(
 	TrxInInnoDB	trx_in_innodb(m_prebuilt->trx);
 
 	if (trx_in_innodb.is_aborted()) {
+		innobase_rollback(ht, m_user_thd, false);
 
-		DBUG_RETURN(innobase_rollback(ht, m_user_thd, false));
+		DBUG_RETURN(convert_error_code_to_mysql(
+			DB_FORCED_ABORT, 0, m_user_thd));
 	}
 
 	trx_start_if_not_started(m_prebuilt->trx, true);
@@ -14463,25 +14951,6 @@ ha_innobase::discard_or_import_tablespace(
 		}
 	}
 
-	if (err == DB_SUCCESS && !discard
-	    && dict_stats_is_persistent_enabled(dict_table)) {
-		dberr_t		ret;
-
-		/* Adjust the persistent statistics. */
-		ret = dict_stats_update(dict_table,
-					DICT_STATS_RECALC_PERSISTENT);
-
-		if (ret != DB_SUCCESS) {
-			push_warning_printf(
-				ha_thd(),
-				Sql_condition::WARN_LEVEL_WARN,
-				ER_ALTER_INFO,
-				"Error updating stats for table '%s'"
-				" after table rebuild: %s",
-				dict_table->name, ut_strerr(ret));
-		}
-	}
-
 	DBUG_RETURN(convert_error_code_to_mysql(err, dict_table->flags, NULL));
 }
 
@@ -14638,6 +15107,39 @@ ha_innobase::delete_table(
 		norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB,
 		false, handler);
 
+	if (err == DB_TABLE_NOT_FOUND
+	    && innobase_get_lower_case_table_names() == 1) {
+		char*	is_part = NULL;
+#ifdef __WIN__
+		is_part = strstr(norm_name, "#p#");
+#else
+		is_part = strstr(norm_name, "#P#");
+#endif /* __WIN__ */
+
+		if (is_part) {
+			char	par_case_name[FN_REFLEN];
+
+#ifndef __WIN__
+			/* Check for the table using lower
+			case name, including the partition
+			separator "P" */
+			strcpy(par_case_name, norm_name);
+			innobase_casedn_str(par_case_name);
+#else
+			/* On Windows platfrom, check
+			whether there exists table name in
+			system table whose name is
+			not being normalized to lower case */
+			normalize_table_name_c_low(
+				par_case_name, name, FALSE);
+#endif
+			err = row_drop_table_for_mysql(
+				par_case_name, trx,
+				thd_sql_command(thd) == SQLCOM_DROP_DB,
+				FALSE);
+		}
+	}
+
 	if (err == DB_TABLE_NOT_FOUND) {
 		/* Test to drop all tables which matches db/tablename + '#'.
 		Only partitions can have '#' as non-first character in
@@ -14725,101 +15227,7 @@ ha_innobase::delete_table(
 	DBUG_RETURN(convert_error_code_to_mysql(err, 0, NULL));
 }
 
-/*****************************************************************//**
-Defragment table.
- at return	error number */
-UNIV_INTERN
-int
-ha_innobase::defragment_table(
-/*==========================*/
-	const char*	name,		/*!< in: table name */
-	const char*	index_name,	/*!< in: index name */
-	bool		async)		/*!< in: whether to wait until finish */
-{
-	char		norm_name[FN_REFLEN];
-	dict_table_t*	table = NULL;
-	dict_index_t*	index = NULL;
-	ibool		one_index = (index_name != 0);
-	int		ret = 0;
-	dberr_t		err = DB_SUCCESS;
-
-	if (!srv_defragment) {
-		return ER_FEATURE_DISABLED;
-	}
-
-	normalize_table_name(norm_name, name);
-
-	table = dict_table_open_on_name(norm_name, FALSE,
-		FALSE, DICT_ERR_IGNORE_NONE);
-
-	for (index = dict_table_get_first_index(table); index;
-	     index = dict_table_get_next_index(index)) {
-
-		if (one_index && strcasecmp(index_name, index->name) != 0) {
-			continue;
-		}
-
-		if (btr_defragment_find_index(index)) {
-			// We borrow this error code. When the same index is
-			// already in the defragmentation queue, issue another
-			// defragmentation only introduces overhead. We return
-			// an error here to let the user know this is not
-			// necessary. Note that this will fail a query that's
-			// trying to defragment a full table if one of the
-			// indicies in that table is already in defragmentation.
-			// We choose this behavior so user is aware of this
-			// rather than silently defragment other indicies of
-			// that table.
-			ret = ER_SP_ALREADY_EXISTS;
-			break;
-		}
-
-		os_event_t event = btr_defragment_add_index(index, async, &err);
-
-		if (err != DB_SUCCESS) {
-			push_warning_printf(
-				current_thd,
-				Sql_condition::WARN_LEVEL_WARN,
-				ER_NO_SUCH_TABLE,
-				"Table %s is encrypted but encryption service or"
-				" used key_id is not available. "
-				" Can't continue checking table.",
-				index->table->name);
-
-			ret = convert_error_code_to_mysql(err, 0, current_thd);
-			break;
-		}
-
-		if (!async && event) {
-			while(os_event_wait_time(event, 1000000)) {
-				if (thd_killed(current_thd)) {
-					btr_defragment_remove_index(index);
-					ret = ER_QUERY_INTERRUPTED;
-					break;
-				}
-			}
-			os_event_destroy(event);
-		}
-
-		if (ret) {
-			break;
-		}
-
-		if (one_index) {
-			one_index = FALSE;
-			break;
-		}
-	}
-
-	dict_table_close(table, FALSE, FALSE);
-
-	if (ret == 0 && one_index) {
-		ret = ER_NO_SUCH_INDEX;
-	}
-
-	return ret;
-}
-
+#ifdef MYSQL_TABLESPACES
 /** Validate the parameters in st_alter_tablespace
 before using them in InnoDB tablespace functions.
 @param[in]	thd		Connection
@@ -14831,16 +15239,15 @@ validate_create_tablespace_info(
 	THD*			thd,
 	st_alter_tablespace*	alter_info)
 {
-	ulint	space_id;
+
+	int error = 0;
 
 	/* The parser ensures that these fields are provided. */
 	ut_a(alter_info->tablespace_name);
 	ut_a(alter_info->data_file_name);
 
 	if (high_level_read_only) {
-		return (HA_ERR_TABLE_READONLY);
-		// JAN: TODO: MySQL 5.7
-		// return(HA_ERR_INNODB_READ_ONLY);
+		return(HA_ERR_INNODB_READ_ONLY);
 	}
 
 	/* From this point forward, push a warning for each problem found
@@ -14857,12 +15264,8 @@ validate_create_tablespace_info(
 				alter_info->tablespace_name);
 		error = HA_ERR_TABLESPACE_EXISTS;
 	}
-
-	/* JAN: TODO: MySQL 5.7 FILE_BLOCK_SIZE
 	if (alter_info->file_block_size) {
-	*/
 		/* Check for a bad file block size. */
-	/*
 		if (!ut_is_2pow(alter_info->file_block_size)
 		    || alter_info->file_block_size < UNIV_ZIP_SIZE_MIN
 		    || alter_info->file_block_size > UNIV_PAGE_SIZE_MAX) {
@@ -14871,9 +15274,9 @@ validate_create_tablespace_info(
 					" FILE_BLOCK_SIZE=%llu", MYF(0),
 					alter_info->file_block_size);
 			error = HA_WRONG_CREATE_OPTION;
-	*/
+
 		/* Don't allow a file block size larger than UNIV_PAGE_SIZE. */
-	/*		} else if (alter_info->file_block_size > UNIV_PAGE_SIZE) {
+		} else if (alter_info->file_block_size > UNIV_PAGE_SIZE) {
 			my_printf_error(ER_ILLEGAL_HA_CREATE_OPTION,
 					"InnoDB: Cannot create a tablespace"
 					" with FILE_BLOCK_SIZE=%llu because"
@@ -14881,9 +15284,9 @@ validate_create_tablespace_info(
 					alter_info->file_block_size,
 					UNIV_PAGE_SIZE);
 			error = HA_WRONG_CREATE_OPTION;
-	*/
+
 		/* Don't allow a compressed tablespace when page size > 16k. */
-	/*		} else if (UNIV_PAGE_SIZE > UNIV_PAGE_SIZE_DEF
+		} else if (UNIV_PAGE_SIZE > UNIV_PAGE_SIZE_DEF
 			   && alter_info->file_block_size != UNIV_PAGE_SIZE) {
 			my_printf_error(ER_ILLEGAL_HA_CREATE_OPTION,
 					"InnoDB: Cannot create a COMPRESSED"
@@ -14892,7 +15295,6 @@ validate_create_tablespace_info(
 			error = HA_WRONG_CREATE_OPTION;
 		}
 	}
-	*/
 
 	/* Validate the ADD DATAFILE name. */
 	char*	filepath = mem_strdup(alter_info->data_file_name);
@@ -14903,20 +15305,17 @@ validate_create_tablespace_info(
 	ulint dirname_len = dirname_length(filepath);
 	const char* basename = filepath + dirname_len;
 	ulint	basename_len = strlen(basename);
-
-	// JAN: TODO: MySQL 5.7 ER_WRONG_FILE_NAME
 	if (basename_len < 5) {
-		my_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
-			MYF(0),
+		my_error(ER_WRONG_FILE_NAME, MYF(0),
 		alter_info->data_file_name);
 		ut_free(filepath);
 		return(HA_WRONG_CREATE_OPTION);
 	}
+
 	if (memcmp(&basename[basename_len - 4], DOT_IBD, 5)) {
-		my_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
-			MYF(0),
+		my_error(ER_WRONG_FILE_NAME, MYF(0),
 			 alter_info->data_file_name);
-		my_printf_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
+		my_printf_error(ER_WRONG_FILE_NAME,
 				"An IBD filepath must end with `.ibd`.",
 				MYF(0));
 		ut_free(filepath);
@@ -14935,10 +15334,9 @@ validate_create_tablespace_info(
 		    || (colon[1] != OS_PATH_SEPARATOR)
 		    || NULL != strchr(&colon[1], ':')) {
 #endif /* _WIN32 */
-			my_error(ER_WRONG_TABLE_NAME, // ER_WRONG_FILE_NAME,
-				MYF(0),
+			my_error(ER_WRONG_FILE_NAME, MYF(0),
 				 alter_info->data_file_name);
-			my_printf_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
+			my_printf_error(ER_WRONG_FILE_NAME,
 					"Invalid use of ':'.", MYF(0));
 			ut_free(filepath);
 			return(HA_WRONG_CREATE_OPTION);
@@ -14961,10 +15359,9 @@ validate_create_tablespace_info(
 	Folder folder(filepath, dirname_len);
 	ut_free(filepath);
 	if (!folder.exists()) {
-		my_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
-			MYF(0),
+		my_error(ER_WRONG_FILE_NAME, MYF(0),
 			 alter_info->data_file_name);
-		my_printf_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
+		my_printf_error(ER_WRONG_FILE_NAME,
 				"The directory does not exist.", MYF(0));
 		return(HA_WRONG_CREATE_OPTION);
 	}
@@ -14972,10 +15369,9 @@ validate_create_tablespace_info(
 	/* CREATE TABLESPACE...ADD DATAFILE can be inside but not under
 	the datadir.*/
 	if (folder_mysql_datadir > folder) {
-		my_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
-			MYF(0),
+		my_error(ER_WRONG_FILE_NAME, MYF(0),
 			 alter_info->data_file_name);
-		my_printf_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
+		my_printf_error(ER_WRONG_FILE_NAME,
 				"CREATE TABLESPACE data file"
 				" cannot be under the datadir.", MYF(0));
 		error = HA_WRONG_CREATE_OPTION;
@@ -14997,7 +15393,7 @@ innobase_create_tablespace(
 	st_alter_tablespace*	alter_info)
 {
 	trx_t*		trx;
-	int		error;
+	int		error=0;
 	Tablespace	tablespace;
 
 	DBUG_ENTER("innobase_create_tablespace");
@@ -15036,13 +15432,12 @@ innobase_create_tablespace(
 	/* In FSP_FLAGS, a zip_ssize of zero means that the tablespace
 	holds non-compresssed tables.  A non-zero zip_ssize means that
 	the general tablespace can ONLY contain compressed tables. */
-	ulint	zip_size = static_cast<ulint>(0);
-	// JAN: TODO: MySQL 5.7
-	//ulint	zip_size = static_cast<ulint>(alter_info->file_block_size);
+	ulint	zip_size = static_cast<ulint>(alter_info->file_block_size);
 	ut_ad(zip_size <= UNIV_PAGE_SIZE_MAX);
 	if (zip_size == 0) {
 		zip_size = UNIV_PAGE_SIZE;
 	}
+
 	bool	zipped = (zip_size != UNIV_PAGE_SIZE);
 	page_size_t	page_size(zip_size, UNIV_PAGE_SIZE, zipped);
 	bool atomic_blobs = page_size.is_compressed();
@@ -15053,8 +15448,7 @@ innobase_create_tablespace(
 		atomic_blobs,	/* needed only for compressed tables */
 		false,		/* This is not a file-per-table tablespace */
 		true,		/* This is a general shared tablespace */
-		false,		/* Temporary General Tablespaces not
-				allowed */
+		false,		/* Temporary General Tablespaces not allowed */
 		false,		/* Page compression is not used. */
 		0,		/* Page compression level 0 */
 		ATOMIC_WRITES_DEFAULT); /* No atomic writes yet */
@@ -15098,8 +15492,7 @@ innobase_drop_tablespace(
 	DBUG_ASSERT(hton == innodb_hton_ptr);
 
 	if (srv_read_only_mode) {
-		DBUG_RETURN(HA_ERR_TABLE_READONLY);
-		//DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
+		DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
 	}
 
 	error = validate_tablespace_name(alter_info->tablespace_name, false);
@@ -15110,16 +15503,21 @@ innobase_drop_tablespace(
 	/* Be sure that this tablespace is known and valid. */
 	space_id = fil_space_get_id_by_name(alter_info->tablespace_name);
 	if (space_id == ULINT_UNDEFINED) {
-		DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
-		// JAN: TODO: MySQL 5.7
-		// DBUG_RETURN(HA_ERR_TABLESPACE_MISSING);
+
+		space_id = dict_space_get_id(alter_info->tablespace_name);
+		if (space_id == ULINT_UNDEFINED) {
+			DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
+			// DBUG_RETURN(HA_ERR_TABLESPACE_MISSING);
+		}
+
+		/* The datafile is not open but the tablespace is in
+		sys_tablespaces, so we can try to drop the metadata. */
 	}
 
 	/* The tablespace can only be dropped if it is empty. */
-	if (!dict_tablespace_is_empty(space_id)) {
+	if (!dict_space_is_empty(space_id)) {
 		DBUG_RETURN(HA_ERR_TABLE_READONLY);
-		// JAN: TODO: MySQL 5.7
-		// DBUG_RETURN(HA_ERR_TABLESPACE_IS_NOT_EMPTY);
+		//DBUG_RETURN(HA_ERR_TABLESPACE_IS_NOT_EMPTY);
 	}
 
 	/* Get the transaction associated with the current thd and make sure
@@ -15144,25 +15542,27 @@ innobase_drop_tablespace(
 		ib::error() << "Unable to delete the dictionary entries"
 			" for tablespace `" << alter_info->tablespace_name
 			<< "`, Space ID " << space_id;
-		error = convert_error_code_to_mysql(err, 0, NULL);
-		trx_rollback_for_mysql(trx);
-		goto cleanup;
+		goto have_error;
 	}
 
 	/* Delete the physical files, fil_space_t & fil_node_t entries. */
 	err = fil_delete_tablespace(space_id, BUF_REMOVE_FLUSH_NO_WRITE);
-	if (err != DB_SUCCESS) {
+	switch (err) {
+	case DB_TABLESPACE_NOT_FOUND:
+		/* OK if the physical file is mising.
+		We deleted the metadata. */
+	case DB_SUCCESS:
+		innobase_commit_low(trx);
+		break;
+	default:
 		ib::error() << "Unable to delete the tablespace `"
 			<< alter_info->tablespace_name
 			<< "`, Space ID " << space_id;
+have_error:
 		error = convert_error_code_to_mysql(err, 0, NULL);
 		trx_rollback_for_mysql(trx);
-		goto cleanup;
 	}
 
-	innobase_commit_low(trx);
-
-cleanup:
 	row_mysql_unlock_data_dictionary(trx);
 	trx_free_for_mysql(trx);
 
@@ -15230,12 +15630,14 @@ innobase_alter_tablespace(
 
 	DBUG_RETURN(error);
 }
+#endif /* MYSQL_TABLESPACES */
 
 /** Remove all tables in the named database inside InnoDB.
 @param[in]	hton	handlerton from InnoDB
 @param[in]	path	Database path; Inside InnoDB the name of the last
 directory in the path is used as the database name.
 For example, in 'mysql/data/test' the database name is 'test'. */
+
 static
 void
 innobase_drop_database(
@@ -15317,7 +15719,7 @@ innobase_drop_database(
 /*********************************************************************//**
 Renames an InnoDB table.
 @return DB_SUCCESS or error code */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+inline MY_ATTRIBUTE((warn_unused_result))
 dberr_t
 innobase_rename_table(
 /*==================*/
@@ -15847,7 +16249,6 @@ ha_innobase::scan_time()
 	it we could end up returning uninitialized value to the caller,
 	which in the worst case could make some query plan go bogus or
 	issue a Valgrind warning. */
-
 	if (m_prebuilt == NULL) {
 		/* In case of derived table, Optimizer will try to fetch stat
 		for table even before table is create or open. In such
@@ -15887,6 +16288,13 @@ ha_innobase::read_time(
 		return(handler::read_time(index, ranges, rows));
 	}
 
+#ifdef MYSQL_ROWS
+	if (rows <= 2) {
+
+		return((double) rows);
+	}
+#endif
+
 	/* Assume that the read time is proportional to the scan time for all
 	rows + at most one seek per range. */
 
@@ -16287,7 +16695,7 @@ ha_innobase::info_low(
 		}
 
 		stats.check_time = 0;
-                stats.mrr_length_per_rec= ref_length +  8; // 8 = max(sizeof(void *));
+		stats.mrr_length_per_rec= ref_length +  8; // 8 = max(sizeof(void *));
 
 		if (stats.records == 0) {
 			stats.mean_rec_length = 0;
@@ -16417,13 +16825,14 @@ ha_innobase::info_low(
 				calculated at different time. This is
 				acceptable. */
 
+#ifdef MYSQL_REC_PER_KEY
 				const rec_per_key_t	rec_per_key
 					= innodb_rec_per_key(
 						index, j,
 						index->table->stat_n_rows);
 
-				// JAN: TODO: MySQL 5.7 New interface
-				// key->set_records_per_key(j, rec_per_key);
+				key->set_records_per_key(j, rec_per_key);
+#endif /* MYSQL_REC_PER_KEY */
 
 				/* The code below is legacy and should be
 				removed together with this comment once we
@@ -16561,61 +16970,156 @@ ha_innobase::enable_indexes(
 	return(error);
 }
 
-/** Disable indexes.
- at param[in]	mode	disable index mode.
- at return HA_ERR_* error code or 0 */
-int
-ha_innobase::disable_indexes(
-	uint	mode)
-{
-	int	error = HA_ERR_WRONG_COMMAND;
+/** Disable indexes.
+ at param[in]	mode	disable index mode.
+ at return HA_ERR_* error code or 0 */
+int
+ha_innobase::disable_indexes(
+	uint	mode)
+{
+	int	error = HA_ERR_WRONG_COMMAND;
+
+	/* Disable index only for intrinsic table. Behavior for all other
+	table continue to remain same. */
+
+	if (dict_table_is_intrinsic(m_prebuilt->table)) {
+		ut_ad(mode == HA_KEY_SWITCH_ALL);
+		for (dict_index_t* index
+			= UT_LIST_GET_FIRST(m_prebuilt->table->indexes);
+		     index != NULL;
+		     index = UT_LIST_GET_NEXT(indexes, index)) {
+
+			/* InnoDB being clustered index we can't disable/enable
+			clustered index itself. */
+			if (dict_index_is_clust(index)) {
+				continue;
+			}
+
+			index->allow_duplicates = true;
+		}
+		error = 0;
+	}
+
+	return(error);
+}
+
+/*
+Updates index cardinalities of the table, based on random dives into
+each index tree. This does NOT calculate exact statistics on the table.
+ at return HA_ADMIN_* error code or HA_ADMIN_OK */
+
+int
+ha_innobase::analyze(
+/*=================*/
+	THD*		thd,		/*!< in: connection thread handle */
+	HA_CHECK_OPT*	check_opt)	/*!< in: currently ignored */
+{
+	/* Simply call info_low() with all the flags
+	and request recalculation of the statistics */
+	int	ret = info_low(
+		HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE,
+		true /* this is ANALYZE */);
+
+	if (ret != 0) {
+		return(HA_ADMIN_FAILED);
+	}
+
+	return(HA_ADMIN_OK);
+}
+
+/*****************************************************************//**
+Defragment table.
+ at return	error number */
+UNIV_INTERN
+int
+ha_innobase::defragment_table(
+/*==========================*/
+	const char*	name,		/*!< in: table name */
+	const char*	index_name,	/*!< in: index name */
+	bool		async)		/*!< in: whether to wait until finish */
+{
+	char		norm_name[FN_REFLEN];
+	dict_table_t*	table = NULL;
+	dict_index_t*	index = NULL;
+	ibool		one_index = (index_name != 0);
+	int		ret = 0;
+	dberr_t		err = DB_SUCCESS;
+
+	if (!srv_defragment) {
+		return ER_FEATURE_DISABLED;
+	}
+
+	normalize_table_name(norm_name, name);
+
+	table = dict_table_open_on_name(norm_name, FALSE,
+		FALSE, DICT_ERR_IGNORE_NONE);
+
+	for (index = dict_table_get_first_index(table); index;
+	     index = dict_table_get_next_index(index)) {
+
+		if (one_index && strcasecmp(index_name, index->name) != 0) {
+			continue;
+		}
+
+		if (btr_defragment_find_index(index)) {
+			// We borrow this error code. When the same index is
+			// already in the defragmentation queue, issue another
+			// defragmentation only introduces overhead. We return
+			// an error here to let the user know this is not
+			// necessary. Note that this will fail a query that's
+			// trying to defragment a full table if one of the
+			// indicies in that table is already in defragmentation.
+			// We choose this behavior so user is aware of this
+			// rather than silently defragment other indicies of
+			// that table.
+			ret = ER_SP_ALREADY_EXISTS;
+			break;
+		}
+
+		os_event_t event = btr_defragment_add_index(index, async, &err);
 
-	/* Disable index only for intrinsic table. Behavior for all other
-	table continue to remain same. */
+		if (err != DB_SUCCESS) {
+			push_warning_printf(
+				current_thd,
+				Sql_condition::WARN_LEVEL_WARN,
+				ER_NO_SUCH_TABLE,
+				"Table %s is encrypted but encryption service or"
+				" used key_id is not available. "
+				" Can't continue checking table.",
+				index->table->name);
 
-	if (dict_table_is_intrinsic(m_prebuilt->table)) {
-		ut_ad(mode == HA_KEY_SWITCH_ALL);
-		for (dict_index_t* index
-			= UT_LIST_GET_FIRST(m_prebuilt->table->indexes);
-		     index != NULL;
-		     index = UT_LIST_GET_NEXT(indexes, index)) {
+			ret = convert_error_code_to_mysql(err, 0, current_thd);
+			break;
+		}
 
-			/* InnoDB being clustered index we can't disable/enable
-			clustered index itself. */
-			if (dict_index_is_clust(index)) {
-				continue;
+		if (!async && event) {
+			while(os_event_wait_time(event, 1000000)) {
+				if (thd_killed(current_thd)) {
+					btr_defragment_remove_index(index);
+					ret = ER_QUERY_INTERRUPTED;
+					break;
+				}
 			}
-
-			index->allow_duplicates = true;
+			os_event_destroy(event);
 		}
-		error = 0;
-	}
 
-	return(error);
-}
+		if (ret) {
+			break;
+		}
 
-/*
-Updates index cardinalities of the table, based on random dives into
-each index tree. This does NOT calculate exact statistics on the table.
- at return HA_ADMIN_* error code or HA_ADMIN_OK */
+		if (one_index) {
+			one_index = FALSE;
+			break;
+		}
+	}
 
-int
-ha_innobase::analyze(
-/*=================*/
-	THD*		thd,		/*!< in: connection thread handle */
-	HA_CHECK_OPT*	check_opt)	/*!< in: currently ignored */
-{
-	/* Simply call info_low() with all the flags
-	and request recalculation of the statistics */
-	int	ret = info_low(
-		HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE,
-		true /* this is ANALYZE */);
+	dict_table_close(table, FALSE, FALSE);
 
-	if (ret != 0) {
-		return(HA_ADMIN_FAILED);
+	if (ret == 0 && one_index) {
+		ret = ER_NO_SUCH_INDEX;
 	}
 
-	return(HA_ADMIN_OK);
+	return ret;
 }
 
 /**********************************************************************//**
@@ -16653,7 +17157,7 @@ ha_innobase::optimize(
 				"InnoDB: Cannot defragment table %s: returned error code %d\n",
 				m_prebuilt->table->name, err);
 
-			if(err == ER_SP_ALREADY_EXISTS) {
+			if (err == ER_SP_ALREADY_EXISTS) {
 				return (HA_ADMIN_OK);
 			} else {
 				return (HA_ADMIN_TRY_ALTER);
@@ -16664,7 +17168,7 @@ ha_innobase::optimize(
 	if (innodb_optimize_fulltext_only) {
 		if (m_prebuilt->table->fts && m_prebuilt->table->fts->cache
 		    && !dict_table_is_discarded(m_prebuilt->table)) {
-			fts_sync_table(m_prebuilt->table, true, false);
+			fts_sync_table(m_prebuilt->table, false, true, false);
 			fts_optimize_table(m_prebuilt->table);
 		}
 		return(HA_ADMIN_OK);
@@ -16727,8 +17231,10 @@ ha_innobase::check(
 		DBUG_RETURN(HA_ADMIN_CORRUPT);
 	}
 
+	m_prebuilt->trx->op_info = "checking table";
+
 	if (m_prebuilt->table->corrupted) {
-		/* If some previous oeration has marked the table as
+		/* If some previous operation has marked the table as
 		corrupted in memory, and has not propagated such to
 		clustered index, we will do so here */
 		index = dict_table_get_first_index(m_prebuilt->table);
@@ -16831,7 +17337,7 @@ ha_innobase::check(
 			if (!dict_index_is_clust(index)) {
 				m_prebuilt->index_usable = FALSE;
 				// row_mysql_lock_data_dictionary(m_prebuilt->trx);
-                                dict_set_corrupted(index, m_prebuilt->trx, "dict_set_index_corrupted");;
+				dict_set_corrupted(index, m_prebuilt->trx, "dict_set_index_corrupted");;
 				// row_mysql_unlock_data_dictionary(m_prebuilt->trx);
 			});
 
@@ -16898,14 +17404,6 @@ ha_innobase::check(
 				index, m_prebuilt->trx, "CHECK TABLE-check index");
 		}
 
-		if (thd_kill_level(m_user_thd)) {
-			break;
-		}
-
-#if 0
-		fprintf(stderr, "%lu entries in index %s\n", n_rows,
-			index->name);
-#endif
 
 		if (index == dict_table_get_first_index(m_prebuilt->table)) {
 			n_rows_in_table = n_rows;
@@ -16999,11 +17497,8 @@ ha_innobase::update_table_comment(
 	} else if (length + flen + 3 > 64000) {
 		flen = 64000 - 3 - length;
 	}
-
 	/* allocate buffer for the full string */
-
 	str = (char*) my_malloc(length + flen + 3, MYF(0));
-
 	if (str) {
 		char* pos	= str + length;
 		if (length) {
@@ -17011,7 +17506,6 @@ ha_innobase::update_table_comment(
 			*pos++ = ';';
 			*pos++ = ' ';
 		}
-
 		memcpy(pos, fk_str.c_str(), flen);
 		pos[flen] = 0;
 	}
@@ -17048,6 +17542,7 @@ ha_innobase::get_foreign_key_create_info(void)
 	trx_search_latch_release_if_reserved(m_prebuilt->trx);
 
 
+
 	/* Output the data to a temporary string */
 	std::string str = dict_print_info_on_foreign_keys(
 		TRUE, m_prebuilt->trx,
@@ -17063,6 +17558,8 @@ ha_innobase::get_foreign_key_create_info(void)
 			my_malloc(PSI_INSTRUMENT_ME, str.length() + 1, MYF(0)));
 	*/
 
+
+
 	if (fk_str) {
 		memcpy(fk_str, str.c_str(), str.length());
 		fk_str[str.length()]='\0';
@@ -17581,7 +18078,7 @@ ha_innobase::end_stmt()
 
 	reset_template();
 
-	//m_ds_mrr.reset();
+	m_ds_mrr.dsmrr_close();
 
 	/* TODO: This should really be reset in reset_template() but for now
 	it's safer to do it explicitly here. */
@@ -17862,6 +18359,14 @@ ha_innobase::external_lock(
 		    && thd_sql_command(thd) == SQLCOM_FLUSH
 		    && lock_type == F_RDLCK) {
 
+			if (dict_table_is_discarded(m_prebuilt->table)) {
+				ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
+					    ER_TABLESPACE_DISCARDED,
+					    table->s->table_name.str);
+
+				DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
+			}
+
 			row_quiesce_table_start(m_prebuilt->table, trx);
 
 			/* Use the transaction instance to track UNLOCK
@@ -18109,9 +18614,9 @@ innodb_show_status(
 
 	/* JAN: TODO: MySQL 5.7 PSI */
 	if (!(str = (char*) my_malloc(
-                                      usable_len + 1, MYF(0)))) {
+				usable_len + 1, MYF(0)))) {
 		/*	if (!(str = (char*) my_malloc(PSI_INSTRUMENT_ME,
-                                      usable_len + 1, MYF(0)))) {
+				usable_len + 1, MYF(0)))) {
 		*/
 		mutex_exit(&srv_monitor_file_mutex);
 		DBUG_RETURN(1);
@@ -18168,7 +18673,7 @@ struct ShowStatus {
 		Value(const char*	name,
 		      ulint		spins,
 		      uint64_t		waits,
-		      ulint		calls)
+		      uint64_t		calls)
 			:
 			m_name(name),
 			m_spins(spins),
@@ -18185,7 +18690,7 @@ struct ShowStatus {
 		ulint			m_spins;
 
 		/** Waits so far */
-		ulint			m_waits;
+		uint64_t		m_waits;
 
 		/** Number of calls so far */
 		uint64_t		m_calls;
@@ -18325,10 +18830,10 @@ ShowStatus::to_string(
 
 		status_len = ut_snprintf(
 			status_buf, sizeof(status_buf),
-			"spins=%lu,waits=%lu,calls=" TRX_ID_FMT,
+			"spins=%lu,waits=%lu,calls=%llu",
 			static_cast<ulong>(it->m_spins),
 			static_cast<long>(it->m_waits),
-			it->m_calls);
+			(ulonglong) it->m_calls);
 
 		if (stat_print(thd, innobase_hton_name,
 			       hton_name_len,
@@ -18519,56 +19024,6 @@ innobase_show_status(
 	return(false);
 }
 
-/** Refresh template for the virtual columns and their base columns if
-the share structure exists
- at param[in]      table           MySQL TABLE
- at param[in]      ib_table        InnoDB dict_table_t
- at param[in]	table_name	table_name used to find the share structure */
-void
-refresh_share_vtempl(
-	const TABLE*		mysql_table,
-	const dict_table_t*	ib_table,
-	const char*		table_name)
-{
-	INNOBASE_SHARE*	share;
-
-	ulint	fold = ut_fold_string(table_name);
-
-	mysql_mutex_lock(&innobase_share_mutex);
-
-	HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
-		    INNOBASE_SHARE*, share,
-		    ut_ad(share->use_count > 0),
-		    !strcmp(share->table_name, table_name));
-
-	if (share == NULL) {
-		/* Partition table does not have "share" structure
-		instantiated, no need to refresh it */
-#ifdef UNIV_DEBUG
- #ifdef _WIN32
-		char*   is_part = strstr(ib_table->name.m_name, "#p#");
- #else
-		char*   is_part = strstr(ib_table->name.m_name, "#P#");
- #endif /* _WIN32 */
-
-		ut_ad(is_part != NULL);
-#endif /* UNIV_DEBUG */
-
-		mysql_mutex_unlock(&innobase_share_mutex);
-		return;
-	}
-
-	free_share_vtemp(share);
-
-	innobase_build_v_templ(
-		mysql_table, ib_table, &(share->s_templ), NULL, true,
-		share->table_name);
-
-	mysql_mutex_unlock(&innobase_share_mutex);
-
-	return;
-}
-
 /************************************************************************//**
 Handling the shared INNOBASE_SHARE structure that is needed to provide table
 locking. Register the table name if it doesn't exist in the hash table. */
@@ -18617,8 +19072,6 @@ get_share(
 		share->idx_trans_tbl.index_mapping = NULL;
 		share->idx_trans_tbl.index_count = 0;
 		share->idx_trans_tbl.array_size = 0;
-		share->s_templ.vtempl = NULL;
-		share->s_templ.n_col = 0;
 	}
 
 	++share->use_count;
@@ -18628,15 +19081,6 @@ get_share(
 	return(share);
 }
 
-/** Free a virtual template in INNOBASE_SHARE structure
- at param[in,out]	share	table share holds the template to free */
-void
-free_share_vtemp(
-	INNOBASE_SHARE*	share)
-{
-	free_vc_templ(&share->s_templ);
-}
-
 /************************************************************************//**
 Free the shared object that was registered with get_share(). */
 static
@@ -18670,8 +19114,6 @@ free_share(
 		/* Free any memory from index translation table */
 		ut_free(share->idx_trans_tbl.index_mapping);
 
-		free_share_vtemp(share);
-
 		my_free(share);
 
 		/* TODO: invoke HASH_MIGRATE if innobase_open_tables
@@ -18883,7 +19325,7 @@ ha_innobase::store_lock(
 	}
 
 #ifdef UNIV_DEBUG
-	if(trx->is_dd_trx) {
+	if (trx->is_dd_trx) {
 		ut_ad(trx->will_lock == 0
 		      && m_prebuilt->select_lock_type == LOCK_NONE);
 	}
@@ -19022,16 +19464,22 @@ ha_innobase::get_auto_increment(
 	/* Not in the middle of a mult-row INSERT. */
 	} else if (m_prebuilt->autoinc_last_value == 0) {
 		set_if_bigger(*first_value, autoinc);
+		/* Check for -ve values. */
+		/* JAN: TODO: MySQL 5.7 : */
+		// } else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) {
+		/* Set to next logical value. */
+		// ut_a(autoinc > trx->n_autoinc_rows);
+		//*first_value = (autoinc - trx->n_autoinc_rows) - 1;
 	}
 
-        if (*first_value > col_max_value) {
-          	/* Out of range number. Let handler::update_auto_increment()
-                   take care of this */
-                m_prebuilt->autoinc_last_value = 0;
-                dict_table_autoinc_unlock(m_prebuilt->table);
-                *nb_reserved_values= 0;
-                return;
-        }
+	if (*first_value > col_max_value) {
+		/* Out of range number. Let handler::update_auto_increment()
+		take care of this */
+		m_prebuilt->autoinc_last_value = 0;
+		dict_table_autoinc_unlock(m_prebuilt->table);
+		*nb_reserved_values= 0;
+		return;
+	}
 
 	*nb_reserved_values = trx->n_autoinc_rows;
 
@@ -19265,7 +19713,6 @@ ha_innobase::register_query_cache_table(
 	ulonglong	*engine_data)	/*!< in/out: data to call_back */
 {
 	*engine_data = 0;
-
 	*call_back = innobase_query_caching_of_table_permitted;
 
 	return(innobase_query_caching_of_table_permitted(
@@ -19363,13 +19810,6 @@ innobase_xa_prepare(
 
 	DBUG_ASSERT(hton == innodb_hton_ptr);
 
-	/* we use support_xa value as it was seen at transaction start
-	time, not the current session variable value. Any possible changes
-	to the session variable take effect only in the next transaction */
-	if (!trx->support_xa) {
-		return(0);
-	}
-
 	thd_get_xid(thd, (MYSQL_XID*) trx->xid);
 
 	/* Release a possible FIFO ticket and search latch. Since we will
@@ -19384,7 +19824,10 @@ innobase_xa_prepare(
 
 	if (trx_in_innodb.is_aborted()) {
 
-		return(innobase_rollback(hton, thd, prepare_trx));
+		innobase_rollback(hton, thd, prepare_trx);
+
+		return(convert_error_code_to_mysql(
+			DB_FORCED_ABORT, 0, thd));
 	}
 
 	if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) {
@@ -19406,7 +19849,11 @@ innobase_xa_prepare(
 		ut_ad(err == DB_SUCCESS || err == DB_FORCED_ABORT);
 
 		if (err == DB_FORCED_ABORT) {
-			return(innobase_rollback(hton, thd, prepare_trx));
+
+			innobase_rollback(hton, thd, prepare_trx);
+
+			return(convert_error_code_to_mysql(
+				DB_FORCED_ABORT, 0, thd));
 		}
 
 	} else {
@@ -19425,6 +19872,24 @@ innobase_xa_prepare(
 		trx_mark_sql_stat_end(trx);
 	}
 
+	if (thd_sql_command(thd) != SQLCOM_XA_PREPARE
+	    && (prepare_trx
+		|| !thd_test_options(
+			thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
+
+		/* For mysqlbackup to work the order of transactions in binlog
+		and InnoDB must be the same. Consider the situation
+
+		  thread1> prepare; write to binlog; ...
+			  <context switch>
+		  thread2> prepare; write to binlog; commit
+		  thread1>			     ... commit
+
+		The server guarantees that writes to the binary log
+		and commits are in the same order, so we do not have
+		to handle this case. */
+	}
+
 	return(0);
 }
 
@@ -19468,7 +19933,7 @@ innobase_commit_by_xid(
 		TrxInInnoDB	trx_in_innodb(trx);
 
 		innobase_commit_low(trx);
-                ut_ad(trx->mysql_thd == NULL);
+		ut_ad(trx->mysql_thd == NULL);
 		/* use cases are: disconnected xa, slave xa, recovery */
 		trx_deregister_from_2pc(trx);
 		ut_ad(!trx->will_lock);    /* trx cache requirement */
@@ -19511,6 +19976,8 @@ innobase_rollback_by_xid(
 	}
 }
 
+#ifdef INNOBASE_CURSOR_VIEW
+
 /*******************************************************************//**
 Create a consistent view for a cursor based on current transaction
 which is created if the corresponding MySQL thread still lacks one.
@@ -19526,9 +19993,7 @@ innobase_create_cursor_view(
 {
 	DBUG_ASSERT(hton == innodb_hton_ptr);
 
-	return NULL;
-	// JAN: TODO: MySQL 5.7 Needed ?
-	//	return(read_cursor_view_create_for_mysql(check_trx_exists(thd)));
+	return(read_cursor_view_create_for_mysql(check_trx_exists(thd)));
 }
 
 /*******************************************************************//**
@@ -19545,10 +20010,8 @@ innobase_close_cursor_view(
 {
 	DBUG_ASSERT(hton == innodb_hton_ptr);
 
-	/* JAN: TODO: MySQL 5.7 Needed
 	read_cursor_view_close_for_mysql(check_trx_exists(thd),
 					 (cursor_view_t*) curview);
-	*/
 }
 
 /*******************************************************************//**
@@ -19566,14 +20029,10 @@ innobase_set_cursor_view(
 {
 	DBUG_ASSERT(hton == innodb_hton_ptr);
 
-	/* JAN: TODO: MySQL 5.7 Needed ?
 	read_cursor_set_for_mysql(check_trx_exists(thd),
 				  (cursor_view_t*) curview);
-	*/
 }
-
-/*******************************************************************//**
-*/
+#endif /* INNOBASE_CURSOR_VIEW */
 
 bool
 ha_innobase::check_if_incompatible_data(
@@ -19650,7 +20109,7 @@ innodb_io_capacity_max_update(
 		srv_io_capacity = in_val;
 
 		push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
-				    ER_WRONG_ARGUMENTS,
+					    ER_WRONG_ARGUMENTS,
 				    "Setting innodb_io_capacity to %lu",
 				    srv_io_capacity);
 	}
@@ -19679,8 +20138,8 @@ innodb_io_capacity_update(
 		push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
 				    ER_WRONG_ARGUMENTS,
 				    "Setting innodb_io_capacity to %lu"
-			" higher than innodb_io_capacity_max %lu",
-			in_val, srv_max_io_capacity);
+				    " higher than innodb_io_capacity_max %lu",
+				    in_val, srv_max_io_capacity);
 
 		srv_max_io_capacity = in_val * 2;
 
@@ -19760,13 +20219,6 @@ innodb_max_dirty_pages_pct_lwm_update(
 	srv_max_dirty_pages_pct_lwm = in_val;
 }
 
-UNIV_INTERN
-void
-ha_innobase::set_partition_owner_stats(ha_statistics *stats)
-{
-	ha_partition_stats= stats;
-}
-
 /************************************************************//**
 Validate the file format name and return its corresponding id.
 @return valid file format id */
@@ -20038,7 +20490,6 @@ innodb_large_prefix_update(
 	void*		var_ptr,
 	const void*	save)
 {
-
 	push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
 		     HA_ERR_WRONG_COMMAND, deprecated_large_prefix);
 
@@ -20071,140 +20522,47 @@ innodb_stopword_table_validate(
 
 	stopword_table_name = value->val_str(value, buff, &len);
 
-	trx = check_trx_exists(thd);
-
-	row_mysql_lock_data_dictionary(trx);
-
-	/* Validate the stopword table's (if supplied) existence and
-	of the right format */
-	if (!stopword_table_name
-	    || fts_valid_stopword_table(stopword_table_name)) {
-		*static_cast<const char**>(save) = stopword_table_name;
-		ret = 0;
-	}
-
-	row_mysql_unlock_data_dictionary(trx);
-
-	return(ret);
-}
-
-/** Update the system variable innodb_buffer_pool_size using the "saved"
-value. This function is registered as a callback with MySQL.
- at param[in]	thd	thread handle
- at param[in]	var	pointer to system variable
- at param[out]	var_ptr	where the formal string goes
- at param[in]	save	immediate result from check function */
-static
-void
-innodb_buffer_pool_size_update(
-	THD*				thd,
-	struct st_mysql_sys_var*	var,
-	void*				var_ptr,
-	const void*			save)
-{
-        longlong	in_val = *static_cast<const longlong*>(save);
-
-	ut_snprintf(export_vars.innodb_buffer_pool_resize_status,
-	        sizeof(export_vars.innodb_buffer_pool_resize_status),
-		"Requested to resize buffer pool.");
-
-	os_event_set(srv_buf_resize_event);
-
-	ib::info() << export_vars.innodb_buffer_pool_resize_status
-		<< " (new size: " << in_val << " bytes)";
-}
-
-/** Validate the requested buffer pool size.  Also, reserve the necessary
-memory needed for buffer pool resize.
- at param[in]	thd	thread handle
- at param[in]	var	pointer to system variable
- at param[out]	save	immediate result for update function
- at param[in]	value	incoming string
- at return 0 on success, 1 on failure.
-*/
-static
-int
-innodb_buffer_pool_size_validate(
-	THD*				thd,
-	struct st_mysql_sys_var*	var,
-	void*				save,
-	struct st_mysql_value*		value)
-{
-	longlong	intbuf;
-
-
-	value->val_int(value, &intbuf);
-
-	if (!srv_was_started) {
-		push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
-				    ER_WRONG_ARGUMENTS,
-				    "Cannot update innodb_buffer_pool_size,"
-				    " because InnoDB is not started.");
-		return(1);
-	}
-
-#ifdef UNIV_DEBUG
-	if (buf_disable_resize_buffer_pool_debug == TRUE) {
-		push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
-			ER_WRONG_ARGUMENTS,
-			"Cannot update innodb_buffer_pool_size,"
-			" because innodb_disable_resize_buffer_pool_debug"
-			" is set.");
-		ib::warn() << "Cannot update innodb_buffer_pool_size,"
-			" because innodb_disable_resize_buffer_pool_debug"
-			" is set.";
-		return(1);
-	}
-#endif /* UNIV_DEBUG */
-
-
-	buf_pool_mutex_enter_all();
-
-	if (srv_buf_pool_old_size != srv_buf_pool_size) {
-		buf_pool_mutex_exit_all();
-		// JAN: TODO: MySQL 5.7 New error
-		// my_error(ER_BUFPOOL_RESIZE_INPROGRESS, MYF(0));
-		my_error(ER_WRONG_ARGUMENTS, MYF(0));
-		return(1);
-	}
-
-	if (srv_buf_pool_instances > 1 && intbuf < BUF_POOL_SIZE_THRESHOLD) {
-		buf_pool_mutex_exit_all();
+	trx = check_trx_exists(thd);
 
-		push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
-				    ER_WRONG_ARGUMENTS,
-				    "Cannot update innodb_buffer_pool_size"
-				    " to less than 1GB if"
-				    " innodb_buffer_pool_instances > 1.");
-		return(1);
+	row_mysql_lock_data_dictionary(trx);
+
+	/* Validate the stopword table's (if supplied) existence and
+	of the right format */
+	if (!stopword_table_name
+	    || fts_valid_stopword_table(stopword_table_name)) {
+		*static_cast<const char**>(save) = stopword_table_name;
+		ret = 0;
 	}
 
-	ulint	requested_buf_pool_size
-		= buf_pool_size_align(static_cast<ulint>(intbuf));
+	row_mysql_unlock_data_dictionary(trx);
 
-	*static_cast<longlong*>(save) = requested_buf_pool_size;
+	return(ret);
+}
 
-	if (srv_buf_pool_size == requested_buf_pool_size) {
-		buf_pool_mutex_exit_all();
-		/* nothing to do */
-		return(0);
-	}
+/** Update the system variable innodb_buffer_pool_size using the "saved"
+value. This function is registered as a callback with MySQL.
+ at param[in]	thd	thread handle
+ at param[in]	var	pointer to system variable
+ at param[out]	var_ptr	where the formal string goes
+ at param[in]	save	immediate result from check function */
+static
+void
+innodb_buffer_pool_size_update(
+	THD*				thd,
+	struct st_mysql_sys_var*	var,
+	void*				var_ptr,
+	const void*			save)
+{
+        longlong	in_val = *static_cast<const longlong*>(save);
 
-	srv_buf_pool_size = requested_buf_pool_size;
-	buf_pool_mutex_exit_all();
+	ut_snprintf(export_vars.innodb_buffer_pool_resize_status,
+	        sizeof(export_vars.innodb_buffer_pool_resize_status),
+		"Requested to resize buffer pool.");
 
-	if (intbuf != static_cast<longlong>(requested_buf_pool_size)) {
-		char	buf[64];
-		int	len = 64;
-		value->val_str(value, buf, &len);
-		push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
-				    ER_TRUNCATED_WRONG_VALUE,
-			"innodb_buffer_pool_size",
-			// mysql_sysvar_buffer_pool_size.name,
-				    value->val_str(value, buf, &len));
-	}
+	os_event_set(srv_buf_resize_event);
 
-	return(0);
+	ib::info() << export_vars.innodb_buffer_pool_resize_status
+		<< " (new size: " << in_val << " bytes)";
 }
 
 /*************************************************************//**
@@ -20391,6 +20749,11 @@ innodb_make_page_dirty(
 		return;
 	}
 
+	if (srv_saved_page_number_debug > space->size) {
+		fil_space_release(space);
+		return;
+	}
+
 	mtr.start();
 	mtr.set_named_space(space);
 
@@ -20829,7 +21192,7 @@ innodb_monitor_validate(
                                          name, MYF(0));
 		*/
 		monitor_name = my_strdup(
-                                         name, MYF(0));
+					name, MYF(0));
 	} else {
 		return(1);
 	}
@@ -21174,9 +21537,9 @@ innodb_defragment_frequency_update(
 static inline char *my_strtok_r(char *str, const char *delim, char **saveptr)
 {
 #if defined _WIN32
-  return strtok_s(str, delim, saveptr);
+	return strtok_s(str, delim, saveptr);
 #else
-  return strtok_r(str, delim, saveptr);
+	return strtok_r(str, delim, saveptr);
 #endif
 }
 
@@ -21310,10 +21673,8 @@ innobase_fts_close_ranking(
 /*=======================*/
 		FT_INFO * fts_hdl)
 {
-	reinterpret_cast<NEW_FT_INFO*>(fts_hdl)->ft_prebuilt->in_fts_query =
-		false;
-
 	fts_result_t*	result;
+
 	result = reinterpret_cast<NEW_FT_INFO*>(fts_hdl)->ft_result;
 
 	fts_query_free_result(result);
@@ -21346,6 +21707,7 @@ innobase_fts_find_ranking(
 }
 
 #ifdef UNIV_DEBUG
+static my_bool	innodb_background_drop_list_empty = TRUE;
 static my_bool	innodb_purge_run_now = TRUE;
 static my_bool	innodb_purge_stop_now = TRUE;
 static my_bool	innodb_log_checkpoint_now = TRUE;
@@ -21353,6 +21715,24 @@ static my_bool	innodb_buf_flush_list_now = TRUE;
 static uint	innodb_merge_threshold_set_all_debug
 	= DICT_INDEX_MERGE_THRESHOLD_DEFAULT;
 
+/** Wait for the background drop list to become empty. */
+static
+void
+wait_background_drop_list_empty(
+	THD*				thd	/*!< in: thread handle */
+					MY_ATTRIBUTE((unused)),
+	struct st_mysql_sys_var*	var	/*!< in: pointer to system
+						variable */
+					MY_ATTRIBUTE((unused)),
+	void*				var_ptr	/*!< out: where the formal
+						string goes */
+					MY_ATTRIBUTE((unused)),
+	const void*			save)	/*!< in: immediate result from
+						check function */
+{
+	row_wait_for_background_drop_list_empty();
+}
+
 /****************************************************************//**
 Set the purge state to RUN. If purge is disabled then it
 is a no-op. This function is registered as a callback with MySQL. */
@@ -21426,7 +21806,11 @@ checkpoint_now_set(
 			fil_flush_file_spaces(FIL_TYPE_LOG);
 		}
 
-		fil_write_flushed_lsn(log_sys->lsn);
+		dberr_t err = fil_write_flushed_lsn(log_sys->lsn);
+
+		if (err != DB_SUCCESS) {
+			ib::warn() << "Checkpoint set failed " << err;
+		}
 	}
 }
 
@@ -21584,13 +21968,13 @@ void
 buffer_pool_load_now(
 /*=================*/
 	THD*				thd	/*!< in: thread handle */
-					__attribute__((unused)),
+					MY_ATTRIBUTE((unused)),
 	struct st_mysql_sys_var*	var	/*!< in: pointer to system
 						variable */
-					__attribute__((unused)),
+					MY_ATTRIBUTE((unused)),
 	void*				var_ptr	/*!< out: where the formal
 						string goes */
-					__attribute__((unused)),
+					MY_ATTRIBUTE((unused)),
 	const void*			save)	/*!< in: immediate result from
 						check function */
 {
@@ -21607,13 +21991,13 @@ void
 buffer_pool_load_abort(
 /*===================*/
 	THD*				thd	/*!< in: thread handle */
-					__attribute__((unused)),
+					MY_ATTRIBUTE((unused)),
 	struct st_mysql_sys_var*	var	/*!< in: pointer to system
 						variable */
-					__attribute__((unused)),
+					MY_ATTRIBUTE((unused)),
 	void*				var_ptr	/*!< out: where the formal
 						string goes */
-					__attribute__((unused)),
+					MY_ATTRIBUTE((unused)),
 	const void*			save)	/*!< in: immediate result from
 						check function */
 {
@@ -22194,6 +22578,12 @@ static MYSQL_SYSVAR_ULONG(idle_flush_pct,
   NULL, NULL, 100, 0, 100, 0);
 
 #ifdef UNIV_DEBUG
+static MYSQL_SYSVAR_BOOL(background_drop_list_empty,
+  innodb_background_drop_list_empty,
+  PLUGIN_VAR_OPCMDARG,
+  "Wait for the background drop list to become empty",
+  NULL, wait_background_drop_list_empty, FALSE);
+
 static MYSQL_SYSVAR_BOOL(purge_run_now, innodb_purge_run_now,
   PLUGIN_VAR_OPCMDARG,
   "Set purge state to RUN",
@@ -22769,7 +23159,7 @@ static MYSQL_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
 static MYSQL_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size,
   PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
   "Size of each log file in a log group.",
-  NULL, NULL, 48*1024*1024L, 1*1024*1024L, LLONG_MAX, 1024*1024L);
+  NULL, NULL, 48*1024*1024L, 4*1024*1024L, LLONG_MAX, 1024*1024L);
 
 static MYSQL_SYSVAR_ULONG(log_files_in_group, srv_n_log_files,
   PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
@@ -22920,12 +23310,12 @@ static MYSQL_SYSVAR_BOOL(use_native_aio, srv_use_native_aio,
   "Use native AIO if supported on this platform.",
   NULL, NULL, TRUE);
 
-#ifdef HAVE_LIBNUMA
+#if defined(HAVE_LIBNUMA) && defined(WITH_NUMA)
 static MYSQL_SYSVAR_BOOL(numa_interleave, srv_numa_interleave,
   PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
   "Use NUMA interleave memory policy to allocate InnoDB buffer pool.",
   NULL, NULL, FALSE);
-#endif // HAVE_LIBNUMA
+#endif /* HAVE_LIBNUMA && WITH_NUMA */
 
 static MYSQL_SYSVAR_BOOL(api_enable_binlog, ib_binlog_enabled,
   PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
@@ -22994,7 +23384,7 @@ static MYSQL_SYSVAR_BOOL(disable_background_merge,
 
 static MYSQL_SYSVAR_ENUM(compress_debug, srv_debug_compress,
   PLUGIN_VAR_RQCMDARG,
-  "Compress all tables, without specifying the COMRPESS table attribute",
+  "Compress all tables, without specifying the COMPRESS table attribute",
   NULL, NULL, Compression::NONE, &innodb_debug_compress_typelib);
 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
 
@@ -23154,16 +23544,34 @@ static MYSQL_SYSVAR_BOOL(disable_resize_buffer_pool_debug,
   "Disable resizing buffer pool to make assertion code not expensive.",
   NULL, NULL, TRUE);
 
+static MYSQL_SYSVAR_BOOL(page_cleaner_disabled_debug,
+  innodb_page_cleaner_disabled_debug,
+  PLUGIN_VAR_OPCMDARG,
+  "Disable page cleaner",
+  NULL, buf_flush_page_cleaner_disabled_debug_update, FALSE);
+
 static MYSQL_SYSVAR_BOOL(sync_debug, srv_sync_debug,
   PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
   "Enable the sync debug checks",
   NULL, NULL, FALSE);
-#endif /* UNIV_DEBUG */
+
+static MYSQL_SYSVAR_BOOL(dict_stats_disabled_debug,
+  innodb_dict_stats_disabled_debug,
+  PLUGIN_VAR_OPCMDARG,
+  "Disable dict_stats thread",
+  NULL, dict_stats_disabled_debug_update, FALSE);
+
+static MYSQL_SYSVAR_BOOL(master_thread_disabled_debug,
+  srv_master_thread_disabled_debug,
+  PLUGIN_VAR_OPCMDARG,
+  "Disable master thread",
+  NULL, srv_master_thread_disabled_debug_update, FALSE);
 
 static MYSQL_SYSVAR_UINT(simulate_comp_failures, srv_simulate_comp_failures,
   PLUGIN_VAR_NOCMDARG,
   "Simulate compression failures.",
   NULL, NULL, 0, 0, 99, 0);
+#endif /* UNIV_DEBUG */
 
 static MYSQL_SYSVAR_BOOL(force_primary_key,
   srv_force_primary_key,
@@ -23443,12 +23851,13 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
   MYSQL_SYSVAR(adaptive_max_sleep_delay),
   MYSQL_SYSVAR(prefix_index_cluster_optimization),
   MYSQL_SYSVAR(thread_sleep_delay),
+  MYSQL_SYSVAR(tmpdir),
   MYSQL_SYSVAR(autoinc_lock_mode),
   MYSQL_SYSVAR(version),
   MYSQL_SYSVAR(use_native_aio),
-#ifdef HAVE_LIBNUMA
+#if defined(HAVE_LIBNUMA) && defined(WITH_NUMA)
   MYSQL_SYSVAR(numa_interleave),
-#endif // HAVE_LIBNUMA
+#endif /* HAVE_LIBNUMA && WITH_NUMA */
   MYSQL_SYSVAR(change_buffering),
   MYSQL_SYSVAR(change_buffer_max_size),
 #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
@@ -23472,6 +23881,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
   MYSQL_SYSVAR(purge_threads),
   MYSQL_SYSVAR(purge_batch_size),
 #ifdef UNIV_DEBUG
+  MYSQL_SYSVAR(background_drop_list_empty),
   MYSQL_SYSVAR(purge_run_now),
   MYSQL_SYSVAR(purge_stop_now),
   MYSQL_SYSVAR(log_checkpoint_now),
@@ -23497,8 +23907,8 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
   MYSQL_SYSVAR(compression_failure_threshold_pct),
   MYSQL_SYSVAR(compression_pad_pct_max),
   MYSQL_SYSVAR(default_row_format),
-  MYSQL_SYSVAR(simulate_comp_failures),
 #ifdef UNIV_DEBUG
+  MYSQL_SYSVAR(simulate_comp_failures),
   MYSQL_SYSVAR(trx_rseg_n_slots_debug),
   MYSQL_SYSVAR(limit_optimistic_insert_debug),
   MYSQL_SYSVAR(trx_purge_view_update_only_debug),
@@ -23506,6 +23916,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
   MYSQL_SYSVAR(saved_page_number_debug),
   MYSQL_SYSVAR(compress_debug),
   MYSQL_SYSVAR(disable_resize_buffer_pool_debug),
+  MYSQL_SYSVAR(page_cleaner_disabled_debug),
+  MYSQL_SYSVAR(dict_stats_disabled_debug),
+  MYSQL_SYSVAR(master_thread_disabled_debug),
   MYSQL_SYSVAR(sync_debug),
 #endif /* UNIV_DEBUG */
   MYSQL_SYSVAR(tmpdir),
@@ -23638,12 +24051,13 @@ ha_innobase::multi_range_read_init(
 	uint		mode,
 	HANDLER_BUFFER*	buf)
 {
-	return(m_ds_mrr.dsmrr_init(this, seq, seq_init_param, n_ranges, mode, buf));
+	return(m_ds_mrr.dsmrr_init(this, seq, seq_init_param,
+				 n_ranges, mode, buf));
 }
 
 int
 ha_innobase::multi_range_read_next(
-	range_id_t	*range_info)
+	range_id_t*		range_info)
 {
 	return(m_ds_mrr.dsmrr_next(range_info));
 }
@@ -23706,17 +24120,16 @@ innobase_index_cond(
 /*================*/
 	void*	file)	/*!< in/out: pointer to ha_innobase */
 {
-  return handler_index_cond_check(file);
+	return handler_index_cond_check(file);
 }
 
-
+#ifdef MYSQL_VIRTUAL_COLUMNS
 /** Get the computed value by supplying the base column values.
 @param[in,out]	table	the table whose virtual column template to be built */
 void
 innobase_init_vc_templ(
 	dict_table_t*	table)
 {
-	THD*    thd = current_thd;
 	char    dbname[MAX_DATABASE_NAME_LEN + 1];
 	char    tbname[MAX_TABLE_NAME_LEN + 1];
 	char*   name = table->name.m_name;
@@ -23725,12 +24138,10 @@ innobase_init_vc_templ(
 	char    t_dbname[MAX_DATABASE_NAME_LEN + 1];
 	char    t_tbname[MAX_TABLE_NAME_LEN + 1];
 
-	/* Acquire innobase_share_mutex to see if table->vc_templ
-	is assigned with its counter part in the share structure */
-	mysql_mutex_lock(&innobase_share_mutex);
+	mutex_enter(&dict_sys->mutex);
 
-	if (table->vc_templ) {
-		mysql_mutex_unlock(&innobase_share_mutex);
+	if (table->vc_templ != NULL) {
+		mutex_exit(&dict_sys->mutex);
 
 		return;
 	}
@@ -23753,8 +24164,8 @@ innobase_init_vc_templ(
 		tbnamelen = is_part - tbname;
 	}
 
-	table->vc_templ = static_cast<innodb_col_templ_t*>(
-		ut_zalloc_nokey(sizeof *(table->vc_templ)));
+	table->vc_templ = UT_NEW_NOKEY(dict_vcol_templ_t());
+	table->vc_templ->vtempl = NULL;
 
 	dbnamelen = filename_to_tablename(dbname, t_dbname,
 					  MAX_DATABASE_NAME_LEN + 1);
@@ -23772,19 +24183,103 @@ innobase_init_vc_templ(
 		static_cast<void*>(table));
 	ut_ad(!ret);
 	*/
-	table->vc_templ_purge = true;
-	mysql_mutex_unlock(&innobase_share_mutex);
+	mutex_exit(&dict_sys->mutex);
+}
+
+/** Change dbname and table name in table->vc_templ.
+ at param[in,out]	table	the table whose virtual column template
+dbname and tbname to be renamed. */
+void
+innobase_rename_vc_templ(
+	dict_table_t*	table)
+{
+	char	dbname[MAX_DATABASE_NAME_LEN + 1];
+	char	tbname[MAX_DATABASE_NAME_LEN + 1];
+	char*	name = table->name.m_name;
+	ulint	dbnamelen = dict_get_db_name_len(name);
+	ulint	tbnamelen = strlen(name) - dbnamelen - 1;
+	char	t_dbname[MAX_DATABASE_NAME_LEN + 1];
+	char	t_tbname[MAX_TABLE_NAME_LEN + 1];
+
+	strncpy(dbname, name, dbnamelen);
+	dbname[dbnamelen] = 0;
+	strncpy(tbname, name + dbnamelen + 1, tbnamelen);
+	tbname[tbnamelen] =0;
+
+	/* For partition table, remove the partition name and use the
+	"main" table name to build the template */
+#ifdef _WIN32
+	char*   is_part = strstr(tbname, "#p#");
+#else
+	char*   is_part = strstr(tbname, "#P#");
+#endif /* _WIN32 */
+
+	if (is_part != NULL) {
+		*is_part = '\0';
+		tbnamelen = is_part - tbname;
+	}
+
+	dbnamelen = filename_to_tablename(dbname, t_dbname,
+					  MAX_DATABASE_NAME_LEN + 1);
+	tbnamelen = filename_to_tablename(tbname, t_tbname,
+					  MAX_TABLE_NAME_LEN + 1);
+
+	table->vc_templ->db_name = t_dbname;
+	table->vc_templ->tb_name = t_tbname;
+}
+
+/** Get the updated parent field value from the update vector for the
+given col_no.
+ at param[in]	foreign		foreign key information
+ at param[in]	update		updated parent vector.
+ at param[in]	col_no		column position of the table
+ at return updated field from the parent update vector, else NULL */
+static
+dfield_t*
+innobase_get_field_from_update_vector(
+	dict_foreign_t*	foreign,
+	upd_t*		update,
+	ulint		col_no)
+{
+	dict_table_t*	parent_table = foreign->referenced_table;
+	dict_index_t*	parent_index = foreign->referenced_index;
+	ulint		parent_field_no;
+	ulint		parent_col_no;
+	ulint		prefix_col_no;
+
+	for (ulint i = 0; i < foreign->n_fields; i++) {
+
+		parent_col_no = dict_index_get_nth_col_no(parent_index, i);
+		parent_field_no = dict_table_get_nth_col_pos(
+			parent_table, parent_col_no, &prefix_col_no);
+
+		for (ulint j = 0; j < update->n_fields; j++) {
+			upd_field_t*	parent_ufield
+				= &update->fields[j];
+
+			if (parent_ufield->field_no == parent_field_no
+			    && parent_col_no == col_no) {
+				return(&parent_ufield->new_val);
+			}
+		}
+	}
+
+	return (NULL);
 }
 
 /** Get the computed value by supplying the base column values.
 @param[in,out]	row		the data row
 @param[in]	col		virtual column
 @param[in]	index		index
- at param[in,out]	my_rec		mysql record to store the data
 @param[in,out]	local_heap	heap memory for processing large data etc.
 @param[in,out]	heap		memory heap that copies the actual index row
 @param[in]	ifield		index field
- at param[in]	in_purge	whether this is called by purge
+ at param[in]	thd		MySQL thread handle
+ at param[in,out]	mysql_table	mysql table object
+ at param[in]	old_table	during ALTER TABLE, this is the old table
+				or NULL.
+ at param[in]	parent_update	update vector for the parent row
+ at param[in]	foreign		foreign key information
 @return the field filled with computed value, or NULL if just want
 to store the value in passed in "my_rec" */
 dfield_t*
@@ -23792,11 +24287,14 @@ innobase_get_computed_value(
 	const dtuple_t*		row,
 	const dict_v_col_t*	col,
 	const dict_index_t*	index,
-	byte*			my_rec,
 	mem_heap_t**		local_heap,
 	mem_heap_t*		heap,
 	const dict_field_t*	ifield,
-	bool			in_purge)
+	THD*			thd,
+	TABLE*			mysql_table,
+	const dict_table_t*	old_table,
+	upd_t*			parent_update,
+	dict_foreign_t*		foreign)
 {
 	byte		rec_buf1[REC_VERSION_56_MAX_INDEX_COL_LEN];
 	byte		rec_buf2[REC_VERSION_56_MAX_INDEX_COL_LEN];
@@ -23804,48 +24302,53 @@ innobase_get_computed_value(
 	byte*		buf;
 	dfield_t*	field;
 	ulint		len;
-	const page_size_t page_size = dict_table_page_size(index->table);
+
+	const page_size_t page_size = (old_table == NULL)
+		? dict_table_page_size(index->table)
+		: dict_table_page_size(old_table);
+
 	ulint		ret = 0;
 
 	ut_ad(index->table->vc_templ);
+	ut_ad(thd != NULL);
 
 	const mysql_row_templ_t*
 			vctempl =  index->table->vc_templ->vtempl[
 				index->table->vc_templ->n_col + col->v_pos];
+
 	if (!heap || index->table->vc_templ->rec_len
 		     >= REC_VERSION_56_MAX_INDEX_COL_LEN) {
 		if (*local_heap == NULL) {
 			*local_heap = mem_heap_create(UNIV_PAGE_SIZE);
 		}
 
-		if (!my_rec) {
-			mysql_rec = static_cast<byte*>(mem_heap_alloc(
-				*local_heap, index->table->vc_templ->rec_len));
-		} else {
-			mysql_rec = my_rec;
-		}
-
+		mysql_rec = static_cast<byte*>(mem_heap_alloc(
+			    *local_heap, index->table->vc_templ->rec_len));
 		buf = static_cast<byte*>(mem_heap_alloc(
 				*local_heap, index->table->vc_templ->rec_len));
 	} else {
-		if (!my_rec) {
-			mysql_rec = rec_buf1;
-		} else {
-			mysql_rec = my_rec;
-		}
-
+		mysql_rec = rec_buf1;
 		buf = rec_buf2;
 	}
 
 	for (ulint i = 0; i < col->num_base; i++) {
 		dict_col_t*			base_col = col->base_col[i];
-		const dfield_t*			row_field;
+		const dfield_t*			row_field = NULL;
 		ulint				col_no = base_col->ind;
 		const mysql_row_templ_t*	templ
 			= index->table->vc_templ->vtempl[col_no];
 		const byte*			data;
 
-		row_field = dtuple_get_nth_field(row, col_no);
+		if (parent_update != NULL) {
+			/** Get the updated field from update vector
+			of the parent table. */
+			row_field = innobase_get_field_from_update_vector(
+					foreign, parent_update, col_no);
+		}
+
+		if (row_field == NULL) {
+			row_field = dtuple_get_nth_field(row, col_no);
+		}
 
 		data = static_cast<const byte*>(row_field->data);
 		len = row_field->len;
@@ -23888,17 +24391,27 @@ innobase_get_computed_value(
 
 	/* Bitmap for specifying which virtual columns the server
 	should evaluate */
-	MY_BITMAP column_map;
-	my_bitmap_map col_map_storage[bitmap_buffer_size(REC_MAX_N_FIELDS)];
+	MY_BITMAP	column_map;
+	my_bitmap_map	col_map_storage[bitmap_buffer_size(REC_MAX_N_FIELDS)];
+
 	bitmap_init(&column_map, col_map_storage, REC_MAX_N_FIELDS, false);
 
 	/* Specify the column the server should evaluate */
 	bitmap_set_bit(&column_map, col->m_col.ind);
 
-	if (in_purge) {
+	if (mysql_table == NULL) {
 		if (vctempl->type == DATA_BLOB) {
-			ulint   max_len = DICT_MAX_FIELD_LEN_BY_FORMAT(
-				index->table) + 1;
+			ulint	max_len;
+
+			if (vctempl->mysql_col_len - 8 == 1) {
+				/* This is for TINYBLOB only, which needs
+				only 1 byte, other BLOBs won't be affected */
+				max_len = 255;
+			} else {
+				max_len = DICT_MAX_FIELD_LEN_BY_FORMAT(
+						index->table) + 1;
+			}
+
 			byte*   blob_mem = static_cast<byte*>(
 				mem_heap_alloc(heap, max_len));
 
@@ -23907,31 +24420,28 @@ innobase_get_computed_value(
 				vctempl->mysql_col_len, blob_mem, max_len);
                 }
 
-		/* JAN: TODO: MySQL 5.7
-		ret = handler::my_eval_gcolumn_expr(
-			current_thd, false, index->table->vc_templ->db_name,
-			index->table->vc_templ->tb_name, &column_map,
+		ret = handler::my_eval_gcolumn_expr_with_open(
+			thd, index->table->vc_templ->db_name.c_str(),
+			index->table->vc_templ->tb_name.c_str(), &column_map,
 			(uchar *)mysql_rec);
-		*/
         } else {
-		/* JAN: TODO: MySQL 5.7
 		ret = handler::my_eval_gcolumn_expr(
-			current_thd, index->table->vc_templ->db_name,
-			index->table->vc_templ->tb_name, &column_map,
+			thd, mysql_table, &column_map,
 			(uchar *)mysql_rec);
-		*/
 	}
 
 	if (ret != 0) {
+#ifdef INNODB_VIRTUAL_DEBUG
 		ib::warn() << "Compute virtual column values failed ";
 		fputs("InnoDB: Cannot compute value for following record ",
 		      stderr);
 		dtuple_print(stderr, row);
+#endif /* INNODB_VIRTUAL_DEBUG */
 		return(NULL);
 	}
 
 	/* we just want to store the data in passed in MySQL record */
-	if (my_rec || ret != 0) {
+	if (ret != 0) {
 		return(NULL);
 	}
 
@@ -23974,6 +24484,7 @@ innobase_get_computed_value(
 
 	return(field);
 }
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 
 /** Attempt to push down an index condition.
 @param[in] keyno MySQL key number
@@ -24032,10 +24543,10 @@ ib_senderrf(
 
 	switch (level) {
 	case IB_LOG_LEVEL_INFO:
-                l = ME_JUST_INFO;
+		l = ME_JUST_INFO;
 		break;
 	case IB_LOG_LEVEL_WARN:
-                l = ME_JUST_WARNING;
+		l = ME_JUST_WARNING;
 		break;
 	case IB_LOG_LEVEL_ERROR:
 		sd_notifyf(0, "STATUS=InnoDB: Error: %s", str);
@@ -24050,7 +24561,7 @@ ib_senderrf(
 		break;
 	}
 
-        my_printv_error(code, format, MYF(l), args);
+	my_printv_error(code, format, MYF(l), args);
 
 	va_end(args);
 	free(str);
@@ -24221,6 +24732,97 @@ ib_warn_row_too_big(const dict_table_t*	table)
 		, prefix ? DICT_MAX_FIXED_COL_LEN : 0);
 }
 
+/** Validate the requested buffer pool size.  Also, reserve the necessary
+memory needed for buffer pool resize.
+ at param[in]	thd	thread handle
+ at param[in]	var	pointer to system variable
+ at param[out]	save	immediate result for update function
+ at param[in]	value	incoming string
+ at return 0 on success, 1 on failure.
+*/
+static
+int
+innodb_buffer_pool_size_validate(
+	THD*				thd,
+	struct st_mysql_sys_var*	var,
+	void*				save,
+	struct st_mysql_value*		value)
+{
+	longlong	intbuf;
+
+
+	value->val_int(value, &intbuf);
+
+	if (!srv_was_started) {
+		push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+				    ER_WRONG_ARGUMENTS,
+				    "Cannot update innodb_buffer_pool_size,"
+				    " because InnoDB is not started.");
+		return(1);
+	}
+
+#ifdef UNIV_DEBUG
+	if (buf_disable_resize_buffer_pool_debug == TRUE) {
+		push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+			ER_WRONG_ARGUMENTS,
+			"Cannot update innodb_buffer_pool_size,"
+			" because innodb_disable_resize_buffer_pool_debug"
+			" is set.");
+		ib::warn() << "Cannot update innodb_buffer_pool_size,"
+			" because innodb_disable_resize_buffer_pool_debug"
+			" is set.";
+		return(1);
+	}
+#endif /* UNIV_DEBUG */
+
+
+	buf_pool_mutex_enter_all();
+
+	if (srv_buf_pool_old_size != srv_buf_pool_size) {
+		buf_pool_mutex_exit_all();
+		my_error(ER_BUFPOOL_RESIZE_INPROGRESS, MYF(0));
+		return(1);
+	}
+
+	if (srv_buf_pool_instances > 1 && intbuf < BUF_POOL_SIZE_THRESHOLD) {
+		buf_pool_mutex_exit_all();
+
+		push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+				    ER_WRONG_ARGUMENTS,
+				    "Cannot update innodb_buffer_pool_size"
+				    " to less than 1GB if"
+				    " innodb_buffer_pool_instances > 1.");
+		return(1);
+	}
+
+	ulint	requested_buf_pool_size
+		= buf_pool_size_align(static_cast<ulint>(intbuf));
+
+	*static_cast<longlong*>(save) = requested_buf_pool_size;
+
+	if (srv_buf_pool_size == requested_buf_pool_size) {
+		buf_pool_mutex_exit_all();
+		/* nothing to do */
+		return(0);
+	}
+
+	srv_buf_pool_size = requested_buf_pool_size;
+	buf_pool_mutex_exit_all();
+
+	if (intbuf != static_cast<longlong>(requested_buf_pool_size)) {
+		char	buf[64];
+		int	len = 64;
+		value->val_str(value, buf, &len);
+		push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+				    ER_TRUNCATED_WRONG_VALUE,
+				    "Truncated incorrect %-.32s value: '%-.128s'",
+				    mysql_sysvar_buffer_pool_size.name,
+				    value->val_str(value, buf, &len));
+	}
+
+	return(0);
+}
+
 /*************************************************************//**
 Check for a valid value of innobase_compression_algorithm.
 @return	0 for valid innodb_compression_algorithm. */
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index b269675..1edd5d3 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -27,11 +27,15 @@ extern const char innobase_index_reserve_name[];
 to explicitly create a file_per_table tablespace for the table. */
 extern const char reserved_file_per_table_space_name[];
 
-/* "innodb_system" tablespace name is reserved by InnoDB for the system tablespace
-which uses space_id 0 and stores extra types of system pages like UNDO
-and doublewrite. */
+/* "innodb_system" tablespace name is reserved by InnoDB for the
+system tablespace which uses space_id 0 and stores extra types of
+system pages like UNDO and doublewrite. */
 extern const char reserved_system_space_name[];
 
+/* "innodb_temporary" tablespace name is reserved by InnoDB for the
+predefined shared temporary tablespace. */
+extern const char reserved_temporary_space_name[];
+
 /* Structure defines translation table between mysql index and InnoDB
 index structures */
 struct innodb_idx_translate_t {
@@ -46,36 +50,6 @@ struct innodb_idx_translate_t {
 					array index */
 };
 
-
-/** Structure defines template related to virtual columns and
-their base columns */
-struct innodb_col_templ_t {
-	/** number of regular columns */
-	ulint			n_col;
-
-	/** number of virtual columns */
-	ulint			n_v_col;
-
-	/** array of templates for virtual col and their base columns */
-	mysql_row_templ_t**	vtempl;
-
-	/** table's database name */
-	char			db_name[MAX_DATABASE_NAME_LEN];
-
-	/** table name */
-	char			tb_name[MAX_TABLE_NAME_LEN];
-
-	/** share->table_name */
-	char			share_name[MAX_DATABASE_NAME_LEN
-					   + MAX_TABLE_NAME_LEN];
-
-	/** MySQL record length */
-	ulint			rec_len;
-
-	/** default column value if any */
-	const byte*		default_rec;
-};
-
 /** InnoDB table share */
 typedef struct st_innobase_share {
 	const char*	table_name;	/*!< InnoDB table name */
@@ -88,9 +62,6 @@ typedef struct st_innobase_share {
 	innodb_idx_translate_t
 			idx_trans_tbl;	/*!< index translation table between
 					MySQL and InnoDB */
-	innodb_col_templ_t
-			s_templ;	/*!< table virtual column template
-					info */
 } INNOBASE_SHARE;
 
 /** Prebuilt structures in an InnoDB table handle used within MySQL */
@@ -112,39 +83,15 @@ struct ha_table_option_struct
 	uint		encryption;		/*!<  DEFAULT, ON, OFF */
 	ulonglong	encryption_key_id;	/*!< encryption key id  */
 };
-
 /* JAN: TODO: MySQL 5.7 handler.h */
 struct st_handler_tablename
 {
   const char *db;
   const char *tablename;
 };
-
 /** The class defining a handle to an Innodb table */
 class ha_innobase: public handler
 {
-	ha_statistics*	ha_partition_stats; /*!< stats of the partition owner
-					handler (if there is one) */
-	uint store_key_val_for_row(uint keynr, char* buff, uint buff_len,
-                                   const uchar* record);
-	inline void update_thd(THD* thd);
-	void update_thd();
-	int change_active_index(uint keynr);
-	int general_fetch(uchar* buf, uint direction, uint match_mode);
-	dberr_t innobase_lock_autoinc();
-	ulonglong innobase_peek_autoinc();
-	dberr_t innobase_set_max_autoinc(ulonglong auto_inc);
-	dberr_t innobase_reset_autoinc(ulonglong auto_inc);
-	dberr_t innobase_get_autoinc(ulonglong* value);
-	void innobase_initialize_autoinc();
-	dict_index_t* innobase_get_index(uint keynr);
-
-#ifdef WITH_WSREP
-	int wsrep_append_keys(THD *thd, bool shared,
-			      const uchar* record0, const uchar* record1);
-#endif
-
-	/* Init values for the class: */
 public:
 	ha_innobase(handlerton* hton, TABLE_SHARE* table_arg);
 	~ha_innobase();
@@ -154,13 +101,21 @@ class ha_innobase: public handler
 	enum row_type get_row_type() const;
 
 	const char* table_type() const;
+
 	const char* index_type(uint key_number);
+
 	const char** bas_ext() const;
+
 	Table_flags table_flags() const;
+
 	ulong index_flags(uint idx, uint part, bool all_parts) const;
+
 	uint max_supported_keys() const;
+
 	uint max_supported_key_length() const;
+
 	uint max_supported_key_part_length() const;
+
 	const key_map* keys_to_use_for_scanning();
 
 	/** Opens dictionary table object using table name. For partition, we need to
@@ -171,136 +126,192 @@ class ha_innobase: public handler
 	@param[in]	is_partition	if this is a partition of a table
 	@param[in]	ignore_err	error to ignore for loading dictionary object
 	@return dictionary table object or NULL if not found */
-	static dict_table_t* open_dict_table(
-	const char*		table_name,
-	const char*		norm_name,
-	bool			is_partition,
-	dict_err_ignore_t	ignore_err);
+        static dict_table_t* open_dict_table(
+		const char*		table_name,
+		const char*		norm_name,
+		bool			is_partition,
+		dict_err_ignore_t	ignore_err);
 
 	int open(const char *name, int mode, uint test_if_locked);
+
 	handler* clone(const char *name, MEM_ROOT *mem_root);
+
 	int close(void);
+
 	double scan_time();
+
 	double read_time(uint index, uint ranges, ha_rows rows);
+
 	longlong get_memory_buffer_size() const;
 
 	int delete_all_rows();
 
 	int write_row(uchar * buf);
+
 	int update_row(const uchar * old_data, uchar * new_data);
+
 	int delete_row(const uchar * buf);
+
 	bool was_semi_consistent_read();
+
 	void try_semi_consistent_read(bool yes);
+
 	void unlock_row();
 
 	int index_init(uint index, bool sorted);
+
 	int index_end();
-	int index_read(uchar * buf, const uchar * key,
-		uint key_len, enum ha_rkey_function find_flag);
-	int index_read_idx(uchar * buf, uint index, const uchar * key,
-			   uint key_len, enum ha_rkey_function find_flag);
+
+	int index_read(
+		uchar*			buf,
+		const uchar*		key,
+		uint			key_len,
+		ha_rkey_function	find_flag);
+
 	int index_read_last(uchar * buf, const uchar * key, uint key_len);
+
 	int index_next(uchar * buf);
+
 	int index_next_same(uchar * buf, const uchar *key, uint keylen);
+
 	int index_prev(uchar * buf);
+
 	int index_first(uchar * buf);
+
 	int index_last(uchar * buf);
 
 	int rnd_init(bool scan);
+
 	int rnd_end();
+
 	int rnd_next(uchar *buf);
+
 	int rnd_pos(uchar * buf, uchar *pos);
 
 	int ft_init();
+
 	void ft_end();
-	FT_INFO *ft_init_ext(uint flags, uint inx, String* key);
-	int ft_read(uchar* buf);
 
-	FT_INFO *ft_init_ext_with_hints(
+	FT_INFO* ft_init_ext(uint flags, uint inx, String* key);
+
+	FT_INFO* ft_init_ext_with_hints(
 		uint			inx,
 		String*			key,
 		void*			hints);
-		/* JAN: TODO: MySQL 5.6
-		Ft_hints*		hints);
-		*/
+		//Ft_hints*		hints);
+
+	int ft_read(uchar* buf);
 
 	int enable_indexes(uint mode);
 	int disable_indexes(uint mode);
 
 	void position(const uchar *record);
+
 	int info(uint);
+
 	int analyze(THD* thd,HA_CHECK_OPT* check_opt);
+
 	int optimize(THD* thd,HA_CHECK_OPT* check_opt);
+
 	int discard_or_import_tablespace(my_bool discard);
-	int extra(enum ha_extra_function operation);
+
+	int extra(ha_extra_function operation);
+
 	int reset();
+
 	int external_lock(THD *thd, int lock_type);
-	int transactional_table_lock(THD *thd, int lock_type);
+
 	int start_stmt(THD *thd, thr_lock_type lock_type);
+
 	void position(uchar *record);
-	ha_rows records_in_range(uint inx, key_range *min_key, key_range
-								*max_key);
+
+	// MySQL 5.7 Select count optimization
+	// int records(ha_rows* num_rows);
+
+	ha_rows records_in_range(
+		uint			inx,
+		key_range*		min_key,
+		key_range*		max_key);
+
 	ha_rows estimate_rows_upper_bound();
 
 	// JAN: TODO: MySQL 5.7
 	// int records(ha_rows* num_rows);
 
 	void update_create_info(HA_CREATE_INFO* create_info);
-	int parse_table_name(const char*name,
-			     HA_CREATE_INFO* create_info,
-			     ulint flags,
-			     ulint flags2,
-			     char* norm_name,
-			     char* temp_path,
-			     char* remote_path);
+
+	int create(
+		const char*		name,
+		TABLE*			form,
+		HA_CREATE_INFO*		create_info);
+
 	const char* check_table_options(THD *thd, TABLE* table,
 		HA_CREATE_INFO*	create_info, const bool use_tablespace, const ulint file_format);
-	int create(const char *name, register TABLE *form,
-					HA_CREATE_INFO *create_info);
+
 	int truncate();
+
 	int delete_table(const char *name);
+
 	int rename_table(const char* from, const char* to);
 	int defragment_table(const char* name, const char* index_name,
 						bool async);
 	int check(THD* thd, HA_CHECK_OPT* check_opt);
 	char* update_table_comment(const char* comment);
+
 	char* get_foreign_key_create_info();
+
 	int get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list);
-	int get_parent_foreign_key_list(THD *thd,
-					List<FOREIGN_KEY_INFO> *f_key_list);
+
+	int get_parent_foreign_key_list(
+		THD*			thd,
+		List<FOREIGN_KEY_INFO>*	f_key_list);
 	int get_cascade_foreign_key_table_list(
 		THD*				thd,
 		List<st_handler_tablename>*	fk_table_list);
 
+
 	bool can_switch_engines();
+
 	uint referenced_by_foreign_key();
+
 	void free_foreign_key_create_info(char* str);
-	THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
-					enum thr_lock_type lock_type);
-	void init_table_handle_for_HANDLER();
-        virtual void get_auto_increment(ulonglong offset, ulonglong increment,
-                                        ulonglong nb_desired_values,
-                                        ulonglong *first_value,
-                                        ulonglong *nb_reserved_values);
-	int reset_auto_increment(ulonglong value);
 
 	uint lock_count(void) const;
 
+	THR_LOCK_DATA** store_lock(
+		THD*			thd,
+		THR_LOCK_DATA**		to,
+		thr_lock_type		lock_type);
+
+	void init_table_handle_for_HANDLER();
+
+	virtual void get_auto_increment(
+		ulonglong		offset,
+		ulonglong		increment,
+		ulonglong		nb_desired_values,
+		ulonglong*		first_value,
+		ulonglong*		nb_reserved_values);
+	int reset_auto_increment(ulonglong value);
+
 	virtual bool get_error_message(int error, String *buf);
+
 	virtual bool get_foreign_dup_key(char*, uint, char*, uint);
+
 	uint8 table_cache_type();
 
 	/**
 	Ask handler about permission to cache table during query registration
 	*/
-	my_bool register_query_cache_table(THD *thd, char *table_key,
-					   uint key_length,
-					   qc_engine_callback *call_back,
-					   ulonglong *engine_data);
-	static const char *get_mysql_bin_log_name();
-	static ulonglong get_mysql_bin_log_pos();
+	my_bool register_query_cache_table(
+		THD*			thd,
+		char*			table_key,
+		uint			key_length,
+		qc_engine_callback*	call_back,
+		ulonglong*		engine_data);
+
 	bool primary_key_is_clustered();
-	int cmp_ref(const uchar *ref1, const uchar *ref2);
+
+	int cmp_ref(const uchar* ref1, const uchar* ref2);
 
 	/** On-line ALTER TABLE interface @see handler0alter.cc @{ */
 
@@ -371,87 +382,74 @@ class ha_innobase: public handler
 		Alter_inplace_info*	ha_alter_info,
 		bool			commit);
 	/** @} */
-	void set_partition_owner_stats(ha_statistics *stats);
-
-	bool check_if_incompatible_data(HA_CREATE_INFO *info,
-					uint table_changes);
-	bool check_if_supported_virtual_columns(void) { return TRUE; }
-
-private:
-	/** Builds a 'template' to the prebuilt struct.
-
-	The template is used in fast retrieval of just those column
-	values MySQL needs in its processing.
-	@param whole_row true if access is needed to a whole row,
-	false if accessing individual fields is enough */
-	void build_template(bool whole_row);
-	/** Resets a query execution 'template'.
-	@see build_template() */
-	inline void reset_template();
 
-	int info_low(uint, bool);
+	bool check_if_incompatible_data(
+		HA_CREATE_INFO*		info,
+		uint			table_changes);
 
-	/** Write Row Interface optimized for Intrinsic table. */
-	int intrinsic_table_write_row(uchar* record);
-
-public:
 	/** @name Multi Range Read interface @{ */
+
 	/** Initialize multi range read @see DsMrr_impl::dsmrr_init
-	* @param seq
-	* @param seq_init_param
-	* @param n_ranges
-	* @param mode
-	* @param buf
-	*/
-	int multi_range_read_init(RANGE_SEQ_IF* seq,
-				  void* seq_init_param,
-				  uint n_ranges, uint mode,
-				  HANDLER_BUFFER* buf);
+	@param seq
+	@param seq_init_param
+	@param n_ranges
+	@param mode
+	@param buf */
+	int multi_range_read_init(
+		RANGE_SEQ_IF*		seq,
+		void*			seq_init_param,
+		uint			n_ranges,
+		uint			mode,
+		HANDLER_BUFFER*		buf);
+
 	/** Process next multi range read @see DsMrr_impl::dsmrr_next
-	* @param range_info
-	*/
-        int multi_range_read_next(range_id_t *range_info);
+	@param range_info */
+	int multi_range_read_next(range_id_t *range_info);
+
 	/** Initialize multi range read and get information.
-	* @see ha_myisam::multi_range_read_info_const
-	* @see DsMrr_impl::dsmrr_info_const
-	* @param keyno
-	* @param seq
-	* @param seq_init_param
-	* @param n_ranges
-	* @param bufsz
-	* @param flags
-	* @param cost
-	*/
-	ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF* seq,
-					   void* seq_init_param,
-					   uint n_ranges, uint* bufsz,
-					   uint* flags, Cost_estimate* cost);
+	@see ha_myisam::multi_range_read_info_const
+	@see DsMrr_impl::dsmrr_info_const
+	@param keyno
+	@param seq
+	@param seq_init_param
+	@param n_ranges
+	@param bufsz
+	@param flags
+	@param cost */
+	ha_rows multi_range_read_info_const(
+		uint			keyno,
+		RANGE_SEQ_IF*		seq,
+		void*			seq_init_param,
+		uint			n_ranges,
+		uint*			bufsz,
+		uint*			flags,
+		Cost_estimate*		cost);
+
 	/** Initialize multi range read and get information.
-	* @see DsMrr_impl::dsmrr_info
-	* @param keyno
-	* @param seq
-	* @param seq_init_param
-	* @param n_ranges
-	* @param bufsz
-	* @param flags
-	* @param cost
-	*/
+	@see DsMrr_impl::dsmrr_info
+	@param keyno
+	@param seq
+	@param seq_init_param
+	@param n_ranges
+	@param bufsz
+	@param flags
+	@param cost */
 	ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
 				      uint key_parts, uint* bufsz, uint* flags,
 				      Cost_estimate* cost);
 
-        int multi_range_read_explain_info(uint mrr_mode,
-                                          char *str, size_t size);
+	int multi_range_read_explain_info(uint mrr_mode,
+					  char *str, size_t size);
 
 	/** Attempt to push down an index condition.
-	* @param[in] keyno	MySQL key number
-	* @param[in] idx_cond	Index condition to be checked
-	* @return idx_cond if pushed; NULL if not pushed
-	*/
-	class Item* idx_cond_push(uint keyno, class Item* idx_cond);
+	@param[in] keyno MySQL key number
+	@param[in] idx_cond Index condition to be checked
+	@return idx_cond if pushed; NULL if not pushed */
+	Item* idx_cond_push(uint keyno, Item* idx_cond);
+	/* @} */
 
-        /* An helper function for index_cond_func_innodb: */
-        bool is_thd_killed();
+	/* An helper function for index_cond_func_innodb: */
+	bool is_thd_killed();
 
 protected:
 
@@ -461,6 +459,42 @@ class ha_innobase: public handler
 	doesn't give any clue that it is called at the end of a statement. */
 	int end_stmt();
 
+	dberr_t innobase_get_autoinc(ulonglong* value);
+	void innobase_initialize_autoinc();
+	dberr_t innobase_lock_autoinc();
+	ulonglong innobase_peek_autoinc();
+	dberr_t innobase_set_max_autoinc(ulonglong auto_inc);
+	dberr_t innobase_reset_autoinc(ulonglong auto_inc);
+
+	/** Resets a query execution 'template'.
+	@see build_template() */
+	void reset_template();
+
+	/** Write Row Interface optimized for Intrinsic table. */
+	int intrinsic_table_write_row(uchar* record);
+
+protected:
+	inline void update_thd(THD* thd);
+	void update_thd();
+
+	int general_fetch(uchar* buf, uint direction, uint match_mode);
+	int change_active_index(uint keynr);
+	dict_index_t* innobase_get_index(uint keynr);
+
+#ifdef WITH_WSREP
+	int wsrep_append_keys(THD *thd, bool shared,
+			      const uchar* record0, const uchar* record1);
+#endif
+	/** Builds a 'template' to the prebuilt struct.
+
+	The template is used in fast retrieval of just those column
+	values MySQL needs in its processing.
+	@param whole_row true if access is needed to a whole row,
+	false if accessing individual fields is enough */
+	void build_template(bool whole_row);
+
+	virtual int info_low(uint, bool);
+
 	/** The multi range read session object */
 	DsMrr_impl		m_ds_mrr;
 
@@ -514,70 +548,51 @@ the definitions are bracketed with #ifdef INNODB_COMPATIBILITY_HOOKS */
 #error InnoDB needs MySQL to be built with #define INNODB_COMPATIBILITY_HOOKS
 #endif
 
+LEX_STRING* thd_query_string(MYSQL_THD thd);
+size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen);
+
 extern "C" {
 
 struct charset_info_st *thd_charset(MYSQL_THD thd);
-LEX_STRING* thd_query_string(MYSQL_THD thd);
 
-/**
-  Check if a user thread is a replication slave thread
-  @param thd  user thread
-  @retval 0 the user thread is not a replication slave thread
-  @retval 1 the user thread is a replication slave thread
-*/
+/** Check if a user thread is a replication slave thread
+ at param thd user thread
+ at retval 0 the user thread is not a replication slave thread
+ at retval 1 the user thread is a replication slave thread */
 int thd_slave_thread(const MYSQL_THD thd);
 
-/**
-  Check if a user thread is running a non-transactional update
-  @param thd  user thread
-  @retval 0 the user thread is not running a non-transactional update
-  @retval 1 the user thread is running a non-transactional update
-*/
+/** Check if a user thread is running a non-transactional update
+ at param thd user thread
+ at retval 0 the user thread is not running a non-transactional update
+ at retval 1 the user thread is running a non-transactional update */
 int thd_non_transactional_update(const MYSQL_THD thd);
 
-/**
-  Get the user thread's binary logging format
-  @param thd  user thread
-  @return Value to be used as index into the binlog_format_names array
-*/
+/** Get the user thread's binary logging format
+ at param thd user thread
+ at return Value to be used as index into the binlog_format_names array */
 int thd_binlog_format(const MYSQL_THD thd);
 
-/**
-  Mark transaction to rollback and mark error as fatal to a sub-statement.
-  @param  thd   Thread handle
-  @param  all   TRUE <=> rollback main transaction.
-*/
-void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all);
-
-/**
-  Check if binary logging is filtered for thread's current db.
-  @param  thd   Thread handle
-  @retval 1 the query is not filtered, 0 otherwise.
-*/
+/** Check if binary logging is filtered for thread's current db.
+ at param thd Thread handle
+ at retval 1 the query is not filtered, 0 otherwise. */
 bool thd_binlog_filter_ok(const MYSQL_THD thd);
 
-/**
-  Check if the query may generate row changes which
-  may end up in the binary.
-  @param  thd   Thread handle
-  @return 1 the query may generate row changes, 0 otherwise.
+/** Check if the query may generate row changes which may end up in the binary.
+ at param thd Thread handle
+ at retval 1 the query may generate row changes, 0 otherwise.
 */
 bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd);
 
-/**
-  Gets information on the durability property requested by
-  a thread.
-  @param  thd   Thread handle
-  @return a durability property.
-*/
-enum durability_properties thd_get_durability_property(const MYSQL_THD thd);
+/** Gets information on the durability property requested by a thread.
+ at param thd Thread handle
+ at return a durability property. */
+durability_properties thd_get_durability_property(const MYSQL_THD thd);
 
 /** Is strict sql_mode set.
- at param thd	Thread object
- at return True if sql_mode has strict mode (all or trans), false otherwise.
-*/
-bool thd_is_strict_mode(const MYSQL_THD thd)
-__attribute__((nonnull));
+ at param thd Thread object
+ at return True if sql_mode has strict mode (all or trans), false otherwise. */
+bool thd_is_strict_mode(const MYSQL_THD thd);
+
 } /* extern "C" */
 
 /** Get the file name and position of the MySQL binlog corresponding to the
@@ -657,50 +672,16 @@ innobase_index_name_is_reserved(
 						created */
 	ulint			num_of_keys)	/*!< in: Number of indexes to
 						be created. */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 extern const char reserved_file_per_table_space_name[];
+
 #ifdef WITH_WSREP
 //extern "C" int wsrep_trx_is_aborting(void *thd_ptr);
 #endif
 
 /** Check if the explicit tablespace targeted is file_per_table.
 @param[in]	create_info	Metadata for the table to create.
-Determines InnoDB table flags.
- at retval true if successful, false if error */
-UNIV_INTERN
-bool
-innobase_table_flags(
-/*=================*/
-	const TABLE*		form,		/*!< in: table */
-	const HA_CREATE_INFO*	create_info,	/*!< in: information
-						on table columns and indexes */
-	THD*			thd,		/*!< in: connection */
-	bool			use_tablespace,	/*!< in: whether to create
-						outside system tablespace */
-	ulint*			flags,		/*!< out: DICT_TF flags */
-	ulint*			flags2)		/*!< out: DICT_TF2 flags */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
-
-/*****************************************************************//**
-Validates the create options. We may build on this function
-in future. For now, it checks two specifiers:
-KEY_BLOCK_SIZE and ROW_FORMAT
-If innodb_strict_mode is not set then this function is a no-op
- at return	NULL if valid, string if not. */
-UNIV_INTERN
-const char*
-create_options_are_invalid(
-/*=======================*/
-	THD*		thd,		/*!< in: connection thread. */
-	TABLE*		form,		/*!< in: information on table
-					columns and indexes */
-	HA_CREATE_INFO*	create_info,	/*!< in: create info. */
-	bool		use_tablespace)	/*!< in: srv_file_per_table */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
-
-/** Check if the explicit tablespace targeted is file_per_table.
- at param[in]	create_info	Metadata for the table to create.
 @return true if the table is intended to use a file_per_table tablespace. */
 UNIV_INLINE
 bool
@@ -712,18 +693,37 @@ tablespace_is_file_per_table(
 			       reserved_file_per_table_space_name)));
 }
 
-/** Check if table will be put in an existing shared general tablespace.
+/** Check if table will be explicitly put in an existing shared general
+or system tablespace.
 @param[in]	create_info	Metadata for the table to create.
- at return true if the table will use an existing shared general tablespace. */
+ at return true if the table will use a shared general or system tablespace. */
 UNIV_INLINE
 bool
 tablespace_is_shared_space(
+const HA_CREATE_INFO*	create_info)
+{
+	return(create_info->tablespace != NULL
+		&& create_info->tablespace[0] != '\0'
+		&& (0 != strcmp(create_info->tablespace,
+		reserved_file_per_table_space_name)));
+}
+
+/** Check if table will be explicitly put in a general tablespace.
+ at param[in]	create_info	Metadata for the table to create.
+ at return true if the table will use a general tablespace. */
+UNIV_INLINE
+bool
+tablespace_is_general_space(
 	const HA_CREATE_INFO*	create_info)
 {
 	return(create_info->tablespace != NULL
-	       && create_info->tablespace[0] != '\0'
-	       && (0 != strcmp(create_info->tablespace,
-			       reserved_file_per_table_space_name)));
+		&& create_info->tablespace[0] != '\0'
+		&& (0 != strcmp(create_info->tablespace,
+				reserved_file_per_table_space_name))
+		&& (0 != strcmp(create_info->tablespace,
+				reserved_temporary_space_name))
+		&& (0 != strcmp(create_info->tablespace,
+				reserved_system_space_name)));
 }
 
 /** Parse hint for table and its indexes, and update the information
@@ -796,6 +796,9 @@ class create_table_info_t
 	/** Validate TABLESPACE option. */
 	bool create_option_tablespace_is_valid();
 
+	/** Validate COMPRESSION option. */
+	bool create_option_compression_is_valid();
+
 	/** Prepare to create a table. */
 	int prepare_create_table(const char*		name);
 
@@ -912,7 +915,8 @@ class create_table_info_t
 	/** Table flags2 */
 	ulint		m_flags2;
 };
-/*********************************************************************//**
+
+/**
 Retrieve the FTS Relevance Ranking result for doc with doc_id
 of prebuilt->fts_doc_id
 @return the relevance ranking value */
@@ -934,9 +938,8 @@ innobase_fts_find_ranking(
 Free the memory for the FTS handler */
 void
 innobase_fts_close_ranking(
-/*=======================*/
-	FT_INFO*	fts_hdl)	/*!< in: FTS handler */
-	MY_ATTRIBUTE((nonnull));
+	FT_INFO*	fts_hdl);	/*!< in: FTS handler */
+
 /**
 Initialize the table FTS stopword list
 @return TRUE if success */
@@ -946,7 +949,7 @@ innobase_fts_load_stopword(
 	dict_table_t*	table,		/*!< in: Table has the FTS */
 	trx_t*		trx,		/*!< in: transaction */
 	THD*		thd)		/*!< in: current thread */
-	MY_ATTRIBUTE((nonnull(1,3), warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Some defines for innobase_fts_check_doc_id_index() return value */
 enum fts_doc_id_index_enum {
@@ -961,7 +964,6 @@ on the Doc ID column.
 @return the status of the FTS_DOC_ID index */
 fts_doc_id_index_enum
 innobase_fts_check_doc_id_index(
-/*============================*/
 	const dict_table_t*	table,		/*!< in: table definition */
 	const TABLE*		altered_table,	/*!< in: MySQL table
 						that is being altered */
@@ -976,22 +978,21 @@ on the Doc ID column in MySQL create index definition.
 FTS_INCORRECT_DOC_ID_INDEX if the FTS_DOC_ID index is of wrong format */
 fts_doc_id_index_enum
 innobase_fts_check_doc_id_index_in_def(
-/*===================================*/
 	ulint		n_key,		/*!< in: Number of keys */
 	const KEY*	key_info)	/*!< in: Key definitions */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
-/***********************************************************************
+/**
 @return version of the extended FTS API */
 uint
 innobase_fts_get_version();
 
-/***********************************************************************
+/**
 @return Which part of the extended FTS API is supported */
 ulonglong
 innobase_fts_flags();
 
-/***********************************************************************
+/**
 Find and Retrieve the FTS doc_id for the current result row
 @return the document ID */
 ulonglong
@@ -999,7 +1000,7 @@ innobase_fts_retrieve_docid(
 /*========================*/
 	FT_INFO_EXT*	fts_hdl);	/*!< in: FTS handler */
 
-/***********************************************************************
+/**
 Find and retrieve the size of the current result
 @return number of matching rows */
 ulonglong
@@ -1007,50 +1008,54 @@ innobase_fts_count_matches(
 /*=======================*/
 	FT_INFO_EXT*	fts_hdl);	/*!< in: FTS handler */
 
-/** "GEN_CLUST_INDEX" is the name reserved for InnoDB default
-system clustered index when there is no primary key. */
-extern const char innobase_index_reserve_name[];
-
-/*********************************************************************//**
+/**
 Copy table flags from MySQL's HA_CREATE_INFO into an InnoDB table object.
 Those flags are stored in .frm file and end up in the MySQL table object,
 but are frequently used inside InnoDB so we keep their copies into the
 InnoDB table object. */
-UNIV_INTERN
 void
 innobase_copy_frm_flags_from_create_info(
-/*=====================================*/
 	dict_table_t*		innodb_table,	/*!< in/out: InnoDB table */
 	const HA_CREATE_INFO*	create_info);	/*!< in: create info */
 
-/*********************************************************************//**
+/**
 Copy table flags from MySQL's TABLE_SHARE into an InnoDB table object.
 Those flags are stored in .frm file and end up in the MySQL table object,
 but are frequently used inside InnoDB so we keep their copies into the
 InnoDB table object. */
-UNIV_INTERN
 void
 innobase_copy_frm_flags_from_table_share(
-/*=====================================*/
 	dict_table_t*		innodb_table,	/*!< in/out: InnoDB table */
 	const TABLE_SHARE*	table_share);	/*!< in: table share */
 
-/********************************************************************//**
-Helper function to push frm mismatch error to error log and
-if needed to sql-layer. */
-UNIV_INTERN
+/** Set up base columns for virtual column
+ at param[in]	table	the InnoDB table
+ at param[in]	field	MySQL field
+ at param[in,out]	v_col	virtual column to be set up */
 void
-ib_push_frm_error(
-/*==============*/
-	THD*		thd,		/*!< in: MySQL thd */
-	dict_table_t*	ib_table,	/*!< in: InnoDB table */
-	TABLE*		table,		/*!< in: MySQL table */
-	ulint		n_keys,		/*!< in: InnoDB #keys */
-	bool		push_warning);	/*!< in: print warning ? */
+innodb_base_col_setup(
+	dict_table_t*	table,
+	const Field*	field,
+	dict_v_col_t*	v_col);
 
+/** Set up base columns for stored column
+ at param[in]	table	InnoDB table
+ at param[in]	field	MySQL field
+ at param[in,out]	s_col	stored column */
+void
+innodb_base_col_setup_for_stored(
+	const dict_table_t*	table,
+	const Field*		field,
+	dict_s_col_t*		s_col);
+
+/** whether this is a stored column */
+// JAN: TODO: MySQL 5.7 virtual fields
+//#define innobase_is_s_fld(field) ((field)->gcol_info && (field)->stored_in_db)
+#define innobase_is_s_fld(field) (field == NULL)
 // JAN: TODO: MySQL 5.7 virtual fields
-// #define innobase_is_v_fld(field) ((field)->gcol_info && !(field)->stored_in_db)
-#define innobase_is_v_fld(field) (false)
+/** whether this is a computed virtual column */
+//#define innobase_is_v_fld(field) ((field)->gcol_info && !(field)->stored_in_db)
+#define innobase_is_v_fld(field) (field == NULL)
 
 /** Release temporary latches.
 Call this function when mysqld passes control to the client. That is to
@@ -1133,28 +1138,11 @@ void
 innobase_build_v_templ(
 	const TABLE*		table,
 	const dict_table_t*	ib_table,
-	innodb_col_templ_t*	s_templ,
+	dict_vcol_templ_t*	s_templ,
 	const dict_add_v_col_t*	add_v,
 	bool			locked,
 	const char*		share_tbl_name);
 
-/** Free a virtual template in INNOBASE_SHARE structure
- at param[in,out]  share   table share holds the template to free */
-void
-free_share_vtemp(
-	INNOBASE_SHARE* share);
-
-/** Refresh template for the virtual columns and their base columns if
-the share structure exists
- at param[in]	table		MySQL TABLE
- at param[in]	ib_table	InnoDB dict_table_t
- at param[in]	table_name	table_name used to find the share structure */
-void
-refresh_share_vtempl(
-	const TABLE*		mysql_table,
-	const dict_table_t*	ib_table,
-	const char*	table_name);
-
 /** callback used by MySQL server layer to initialized
 the table virtual columns' template
 @param[in]	table		MySQL TABLE
@@ -1168,25 +1156,32 @@ innobase_build_v_templ_callback(
 the table virtual columns' template */
 typedef void (*my_gcolumn_templatecallback_t)(const TABLE*, void*);
 
-/** Get the computed value by supplying the base column values.
- at param[in,out]  table   the table whose virtual column template to be built */
-void
-innobase_init_vc_templ(
-        dict_table_t*   table);
-
-/** Free the virtual column template
- at param[in,out]  vc_templ        virtual column template */
-void
-free_vc_templ(
-	innodb_col_templ_t*	vc_templ);
-
-/** Set up base columns for virtual column
- at param[in]	table		InnoDB table
- at param[in]	field		MySQL field
- at param[in,out]	v_col		virtual column */
+/********************************************************************//**
+Helper function to push frm mismatch error to error log and
+if needed to sql-layer. */
+UNIV_INTERN
 void
-innodb_base_col_setup(
-	dict_table_t*	table,
-	const Field*	field,
-	dict_v_col_t*	v_col);
+ib_push_frm_error(
+/*==============*/
+	THD*		thd,		/*!< in: MySQL thd */
+	dict_table_t*	ib_table,	/*!< in: InnoDB table */
+	TABLE*		table,		/*!< in: MySQL table */
+	ulint		n_keys,		/*!< in: InnoDB #keys */
+	bool		push_warning);	/*!< in: print warning ? */
 
+/*****************************************************************//**
+Validates the create options. We may build on this function
+in future. For now, it checks two specifiers:
+KEY_BLOCK_SIZE and ROW_FORMAT
+If innodb_strict_mode is not set then this function is a no-op
+ at return	NULL if valid, string if not. */
+UNIV_INTERN
+const char*
+create_options_are_invalid(
+/*=======================*/
+	THD*		thd,		/*!< in: connection thread. */
+	TABLE*		form,		/*!< in: information on table
+					columns and indexes */
+	HA_CREATE_INFO*	create_info,	/*!< in: create info. */
+	bool		use_tablespace)	/*!< in: srv_file_per_table */
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
diff --git a/storage/innobase/handler/ha_innopart.cc b/storage/innobase/handler/ha_innopart.cc
index 855090a..5fd02df 100644
--- a/storage/innobase/handler/ha_innopart.cc
+++ b/storage/innobase/handler/ha_innopart.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2014, 2016, 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
@@ -79,8 +79,7 @@ Ha_innopart_share::Ha_innopart_share(
 	m_tot_parts(),
 	m_index_count(),
 	m_ref_count(),
-	m_table_share(table_share),
-	m_s_templ()
+	m_table_share(table_share)
 {}
 
 Ha_innopart_share::~Ha_innopart_share()
@@ -94,11 +93,6 @@ Ha_innopart_share::~Ha_innopart_share()
 		ut_free(m_index_mapping);
 		m_index_mapping = NULL;
 	}
-	if (m_s_templ != NULL) {
-		free_vc_templ(m_s_templ);
-		ut_free(m_s_templ);
-		m_s_templ = NULL;
-	}
 }
 
 /** Fold to lower case if windows or lower_case_table_names == 1.
@@ -229,25 +223,27 @@ Ha_innopart_share::set_v_templ(
 	dict_table_t*	ib_table,
 	const char*	name)
 {
-#ifndef DBUG_OFF
-	if (m_table_share->tmp_table == NO_TMP_TABLE) {
-		mysql_mutex_assert_owner(&m_table_share->LOCK_ha_data);
-	}
-#endif /* DBUG_OFF */
+	ut_ad(mutex_own(&dict_sys->mutex));
 
 	if (ib_table->n_v_cols > 0) {
-		if (!m_s_templ) {
-			m_s_templ = static_cast<innodb_col_templ_t*>(
-				ut_zalloc_nokey( sizeof *m_s_templ));
-			innobase_build_v_templ(table, ib_table,
-					       m_s_templ, NULL, false, name);
-
-			for (ulint i = 0; i < m_tot_parts; i++) {
-				m_table_parts[i]->vc_templ = m_s_templ;
+		for (ulint i = 0; i < m_tot_parts; i++) {
+			if (m_table_parts[i]->vc_templ == NULL) {
+				m_table_parts[i]->vc_templ
+					= UT_NEW_NOKEY(dict_vcol_templ_t());
+				m_table_parts[i]->vc_templ->vtempl = NULL;
+			} else if (m_table_parts[i]->get_ref_count() == 1) {
+				/* Clean and refresh the template */
+				dict_free_vc_templ(m_table_parts[i]->vc_templ);
+				m_table_parts[i]->vc_templ->vtempl = NULL;
+			}
+
+			if (m_table_parts[i]->vc_templ->vtempl == NULL) {
+				innobase_build_v_templ(
+					table, ib_table,
+					m_table_parts[i]->vc_templ,
+					NULL, true, name);
 			}
 		}
-	} else {
-		ut_ad(!m_s_templ);
 	}
 }
 
@@ -467,12 +463,6 @@ Ha_innopart_share::close_table_parts()
 		m_index_mapping = NULL;
 	}
 
-	if (m_s_templ != NULL) {
-		free_vc_templ(m_s_templ);
-		ut_free(m_s_templ);
-		m_s_templ = NULL;
-	}
-
 	m_tot_parts = 0;
 	m_index_count = 0;
 }
@@ -1128,10 +1118,13 @@ ha_innopart::open(
 	m_prebuilt->default_rec = table->s->default_values;
 	ut_ad(m_prebuilt->default_rec);
 
+	DBUG_ASSERT(table != NULL);
+	m_prebuilt->m_mysql_table = table;
+
 	if (ib_table->n_v_cols > 0) {
-		lock_shared_ha_data();
+		mutex_enter(&dict_sys->mutex);
 		m_part_share->set_v_templ(table, ib_table, name);
-		unlock_shared_ha_data();
+		mutex_exit(&dict_sys->mutex);
 	}
 
 	/* Looks like MySQL-3.23 sometimes has primary key number != 0. */
@@ -1763,6 +1756,9 @@ ha_innopart::index_init(
 		m_prebuilt->m_no_prefetch = true;
 	}
 
+	/* For scan across partitions, the keys needs to be materialized */
+	m_prebuilt->m_read_virtual_key = true;
+
 	error = change_active_index(part_id, keynr);
 	if (error != 0) {
 		destroy_record_priority_queue();
@@ -1787,12 +1783,14 @@ ha_innopart::index_end()
 
 	if (part_id == MY_BIT_NONE) {
 		/* Never initialized any index. */
+		active_index = MAX_KEY;
 		DBUG_RETURN(0);
 	}
 	if (m_ordered) {
 		destroy_record_priority_queue();
 		m_prebuilt->m_no_prefetch = false;
 	}
+	m_prebuilt->m_read_virtual_key = false;
 
 	DBUG_RETURN(ha_innobase::index_end());
 }
@@ -2119,7 +2117,7 @@ ha_innopart::index_next_in_part(
 	ut_ad(m_ordered_scan_ongoing
 	      || m_ordered_rec_buffer == NULL
 	      || m_prebuilt->used_in_HANDLER
-	      || m_part_info->num_partitions_used() <= 1);
+	      || m_part_spec.start_part >= m_part_spec.end_part);
 
 	DBUG_RETURN(error);
 }
@@ -2182,7 +2180,7 @@ ha_innopart::index_prev_in_part(
 	ut_ad(m_ordered_scan_ongoing
 	      || m_ordered_rec_buffer == NULL
 	      || m_prebuilt->used_in_HANDLER
-	      || m_part_info->num_partitions_used() <= 1);
+	      || m_part_spec.start_part >= m_part_spec.end_part);
 
 	return(error);
 }
@@ -2553,6 +2551,19 @@ ha_innopart::update_part_elem(
 					ib_table->tablespace);
 		}
 	}
+	else {
+		ut_ad(part_elem->tablespace_name == NULL
+		      || 0 == strcmp(part_elem->tablespace_name,
+				     "innodb_file_per_table"));
+		if (part_elem->tablespace_name != NULL
+		    && 0 != strcmp(part_elem->tablespace_name,
+				   "innodb_file_per_table")) {
+
+			/* Update part_elem tablespace to NULL same as in
+			innodb data dictionary ib_table. */
+			part_elem->tablespace_name = NULL;
+		}
+	}
 }
 
 /** Update create_info.
@@ -3537,14 +3548,31 @@ ha_innopart::info_low(
 					checked_sys_tablespace = true;
 				}
 
-				ulint	space = static_cast<ulint>(
+				uintmax_t	space =
 					fsp_get_available_space_in_free_extents(
-						ib_table->space));
-				if (space == ULINT_UNDEFINED) {
-					ut_ad(0);
-					avail_space = space;
+						ib_table->space);
+				if (space == UINTMAX_MAX) {
+					THD*	thd = ha_thd();
+					const char* table_name
+						= ib_table->name.m_name;
+
+					push_warning_printf(
+						thd,
+						Sql_condition::SL_WARNING,
+						ER_CANT_GET_STAT,
+						"InnoDB: Trying to get the"
+						" free space for partition %s"
+						" but its tablespace has been"
+						" discarded or the .ibd file"
+						" is missing. Setting the free"
+						" space of the partition to"
+						" zero.",
+						ut_get_name(
+							m_prebuilt->trx,
+							table_name).c_str());
 				} else {
-					avail_space += space;
+					avail_space +=
+						static_cast<ulint>(space);
 				}
 			}
 		}
@@ -3598,35 +3626,7 @@ ha_innopart::info_low(
 		if ((flag & HA_STATUS_NO_LOCK) == 0
 		    && (flag & HA_STATUS_VARIABLE_EXTRA) != 0
 		    && srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {
-
-			if (avail_space == ULINT_UNDEFINED) {
-				THD*	thd;
-				char	errbuf[MYSYS_STRERROR_SIZE];
-
-				thd = ha_thd();
-
-				std::string err_str;
-				err_str = "InnoDB: Trying to get"
-					" the free space for table ";
-				err_str += ut_get_name(m_prebuilt->trx,
-						ib_table->name.m_name);
-				err_str += " but its tablespace has been"
-					" discarded or the .ibd file is"
-					" missing. Setting the free space to"
-					" zero.";
-				push_warning_printf(
-					thd,
-					Sql_condition::SL_WARNING,
-					ER_CANT_GET_STAT,
-					err_str.c_str(),
-					errno,
-					my_strerror(errbuf, sizeof(errbuf),
-						    errno));
-
-				stats.delete_length = 0;
-			} else {
-				stats.delete_length = avail_space * 1024;
-			}
+			stats.delete_length = avail_space * 1024;
 		}
 
 		stats.check_time = 0;
@@ -4085,6 +4085,39 @@ ha_innopart::start_stmt(
 	return(error);
 }
 
+/** Function to store lock for all partitions in native partitioned table. Also
+look at ha_innobase::store_lock for more details.
+ at param[in]	thd		user thread handle
+ at param[in]	to		pointer to the current element in an array of
+pointers to lock structs
+ at param[in]	lock_type	lock type to store in 'lock'; this may also be
+TL_IGNORE
+ at retval	to	pointer to the current element in the 'to' array */
+THR_LOCK_DATA**
+ha_innopart::store_lock(
+	THD*			thd,
+	THR_LOCK_DATA**		to,
+	thr_lock_type		lock_type)
+{
+	trx_t*  trx = m_prebuilt->trx;
+	const uint sql_command = thd_sql_command(thd);
+
+	ha_innobase::store_lock(thd, to, lock_type);
+
+	if (sql_command == SQLCOM_FLUSH
+	    && lock_type == TL_READ_NO_INSERT) {
+		for (uint i = 1; i < m_tot_parts; i++) {
+			dict_table_t* table = m_part_share->get_table_part(i);
+
+			dberr_t err = row_quiesce_set_state(
+				table, QUIESCE_START, trx);
+			ut_a(err == DB_SUCCESS || err == DB_UNSUPPORTED);
+		}
+	}
+
+	return to;
+}
+
 /** Lock/prepare to lock table.
 As MySQL will execute an external lock for every new table it uses when it
 starts to process an SQL statement (an exception is when MySQL calls
@@ -4102,8 +4135,6 @@ ha_innopart::external_lock(
 	int	lock_type)
 {
 	int	error = 0;
-	bool	is_quiesce_set = false;
-	bool	is_quiesce_start = false;
 
 	if (m_part_info->get_first_used_partition() == MY_BIT_NONE
 		&& !(m_mysql_has_locked
@@ -4116,63 +4147,55 @@ ha_innopart::external_lock(
 	ut_ad(m_mysql_has_locked || lock_type != F_UNLCK);
 
 	m_prebuilt->table = m_part_share->get_table_part(0);
-	switch (m_prebuilt->table->quiesce) {
-	case QUIESCE_START:
-		/* Check for FLUSH TABLE t WITH READ LOCK; */
-		if (!srv_read_only_mode
-		    && thd_sql_command(thd) == SQLCOM_FLUSH
-		    && lock_type == F_RDLCK) {
-
-			is_quiesce_set = true;
-			is_quiesce_start = true;
-		}
-		break;
+	error = ha_innobase::external_lock(thd, lock_type);
 
-	case QUIESCE_COMPLETE:
-		/* Check for UNLOCK TABLES; implicit or explicit
-		or trx interruption. */
-		if (m_prebuilt->trx->flush_tables > 0
-		    && (lock_type == F_UNLCK
-			|| trx_is_interrupted(m_prebuilt->trx))) {
+        for (uint i = 0; i < m_tot_parts; i++) {
+		dict_table_t* table = m_part_share->get_table_part(i);
 
-			is_quiesce_set = true;
-		}
+		switch (table->quiesce) {
+		case QUIESCE_START:
+			/* Check for FLUSH TABLE t WITH READ LOCK */
+			if (!srv_read_only_mode
+			    && thd_sql_command(thd) == SQLCOM_FLUSH
+			    && lock_type == F_RDLCK) {
 
-		break;
+				ut_ad(table->quiesce == QUIESCE_START);
 
-	case QUIESCE_NONE:
-		break;
-	default:
-		ut_ad(0);
-	}
+				row_quiesce_table_start(table,
+							m_prebuilt->trx);
 
-	error = ha_innobase::external_lock(thd, lock_type);
+				/* Use the transaction instance to track
+				UNLOCK TABLES. It can be done via START
+				TRANSACTION; too implicitly. */
 
-	/* FLUSH FOR EXPORT is done above only for the first partition,
-	so complete it for all the other partitions. */
-	if (is_quiesce_set) {
-		for (uint i = 1; i < m_tot_parts; i++) {
-			dict_table_t* table = m_part_share->get_table_part(i);
-			if (is_quiesce_start) {
-				table->quiesce = QUIESCE_START;
-				row_quiesce_table_start(table, m_prebuilt->trx);
+				++m_prebuilt->trx->flush_tables;
+			}
+			break;
 
-				/* Use the transaction instance to track UNLOCK
-				TABLES. It can be done via START TRANSACTION;
-				too implicitly. */
+		case QUIESCE_COMPLETE:
+			/* Check for UNLOCK TABLES; implicit or explicit
+			or trx interruption. */
+			if (m_prebuilt->trx->flush_tables > 0
+			    && (lock_type == F_UNLCK
+				|| trx_is_interrupted(m_prebuilt->trx))) {
 
-				++m_prebuilt->trx->flush_tables;
-			} else {
 				ut_ad(table->quiesce == QUIESCE_COMPLETE);
 				row_quiesce_table_complete(table,
-					m_prebuilt->trx);
+							   m_prebuilt->trx);
 
 				ut_a(m_prebuilt->trx->flush_tables > 0);
 				--m_prebuilt->trx->flush_tables;
 			}
+			break;
+
+		case QUIESCE_NONE:
+			break;
+
+		default:
+			ut_ad(0);
 		}
-		m_prebuilt->table = m_part_share->get_table_part(0);
 	}
+
 	ut_ad(!m_auto_increment_lock);
 	ut_ad(!m_auto_increment_safe_stmt_log_lock);
 
diff --git a/storage/innobase/handler/ha_innopart.h b/storage/innobase/handler/ha_innopart.h
index 0a6bfe0..8caa9cd 100644
--- a/storage/innobase/handler/ha_innopart.h
+++ b/storage/innobase/handler/ha_innopart.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2014, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, 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
@@ -21,9 +21,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
 #ifndef ha_innopart_h
 #define ha_innopart_h
 
-/* JAN: TODO: MySQL 5.7 */
-//#include "partitioning/partition_handler.h"
-#include "ha_partition.h"
+#include "partitioning/partition_handler.h"
 
 /* Forward declarations */
 class Altered_partitions;
@@ -62,8 +60,6 @@ class Ha_innopart_share : public Partition_share
 	/** Pointer back to owning TABLE_SHARE. */
 	TABLE_SHARE*		m_table_share;
 
-	/** Virtual column template */
-	innodb_col_templ_t*	m_s_templ;
 public:
 	Ha_innopart_share(
 		TABLE_SHARE*	table_share);
@@ -188,7 +184,7 @@ truncate_partition.
 InnoDB specific functions related to partitioning is implemented here. */
 class ha_innopart:
 	public ha_innobase,
-//	public Partition_helper,
+	public Partition_helper,
 	public Partition_handler
 {
 public:
@@ -509,9 +505,7 @@ class ha_innopart:
 	ft_init_ext_with_hints(
 		uint		inx,
 		String*		key,
-		/* JAN: TODO: MySQL 5. /
-		Ft_hints*	hints)*/
-		void*		hints)
+		Ft_hints*	hints)
 	{
 		ut_ad(0);
 		return(NULL);
@@ -613,7 +607,7 @@ class ha_innopart:
 
 	uint
 	alter_flags(
-		uint	flags __attribute__((unused))) const
+		uint	flags MY_ATTRIBUTE((unused))) const
 	{
 		return(HA_PARTITION_FUNCTION_SUPPORTED
 		       | HA_FAST_CHANGE_PARTITION);
@@ -1124,6 +1118,12 @@ class ha_innopart:
 		THD*	thd,
 		int	lock_type);
 
+	THR_LOCK_DATA**
+	store_lock(
+		THD*			thd,
+		THR_LOCK_DATA**		to,
+		thr_lock_type		lock_type);
+
 	int
 	write_row(
 		uchar*	record)
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 5f421d4..79eaabd 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2005, 2016, Oracle and/or its affiliates
+Copyright (c) 2005, 2016, Oracle and/or its affiliates. All Rights Reserved.
 Copyright (c) 2013, 2016, MariaDB Corporation. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
@@ -82,14 +82,14 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_REBUILD
 	| Alter_inplace_info::ALTER_COLUMN_ORDER
 	| Alter_inplace_info::DROP_COLUMN
 	| Alter_inplace_info::ADD_COLUMN
-	/* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_STORED_COLUMNS
 	| Alter_inplace_info::ALTER_STORED_COLUMN_ORDER
 	| Alter_inplace_info::DROP_STORED_COLUMN
-	| Alter_inplace_info::ADD_STORED_COLUMN
-	*/
+	| Alter_inplace_info::ADD_STORED_BASE_COLUMN
+	| Alter_inplace_info::ALTER_STORED_COLUMN_TYPE
+#endif
 	| Alter_inplace_info::RECREATE_TABLE
 	/*
-	| Alter_inplace_info::ALTER_STORED_COLUMN_TYPE
 	*/
 	;
 
@@ -103,6 +103,9 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_INPLACE_IGNORE
 	| Alter_inplace_info::ALTER_PARTITIONED
 	| Alter_inplace_info::ALTER_COLUMN_COLUMN_FORMAT
 	| Alter_inplace_info::ALTER_COLUMN_STORAGE_TYPE
+#ifdef MYSQL_VIRTUAL_COLUMNS
+	| Alter_inplace_info::ALTER_VIRTUAL_GCOL_EXPR
+#endif
 	| Alter_inplace_info::ALTER_RENAME;
 
 /** Operations on foreign key definitions (changing the schema only) */
@@ -116,19 +119,19 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_NOREBUILD
 	| INNOBASE_FOREIGN_OPERATIONS
 	| Alter_inplace_info::DROP_INDEX
 	| Alter_inplace_info::DROP_UNIQUE_INDEX
-	/* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_RENAME_INDEX
 	| Alter_inplace_info::RENAME_INDEX
-	*/
+#endif
 	| Alter_inplace_info::ALTER_COLUMN_NAME
 	| Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH;
-	/* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_VIRTUAL_COLUMNS
 	| Alter_inplace_info::ALTER_INDEX_COMMENT
 	| Alter_inplace_info::ADD_VIRTUAL_COLUMN
 	| Alter_inplace_info::DROP_VIRTUAL_COLUMN
-	| Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER;
-	*/
-	/* | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_TYPE; */
-
+	| Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER
+	| Alter_inplace_info::ALTER_VIRTUAL_COLUMN_TYPE
+#endif
+	;
 struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
 {
 	/** Dummy query graph */
@@ -248,7 +251,8 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
 		}
 #endif /* UNIV_DEBUG */
 
-		thr = pars_complete_graph_for_exec(NULL, prebuilt->trx, heap);
+		thr = pars_complete_graph_for_exec(NULL, prebuilt->trx, heap,
+			prebuilt);
 	}
 
 	~ha_innobase_inplace_ctx()
@@ -309,14 +313,7 @@ my_error_innodb(
 		ut_error;
 		break;
 	case DB_TEMP_FILE_WRITE_FAIL:
-		/* JAN: TODO: MySQL 5.7
-		my_error(ER_GET_ERRMSG, MYF(0),
-                         DB_TEMP_FILE_WRITE_FAILURE,
-                         ut_strerr(DB_TEMP_FILE_WRITE_FAILURE),
-                         "InnoDB");
-		*/
-		my_error(ER_OUT_OF_RESOURCES, MYF(0));
-
+		my_error(ER_TEMP_FILE_WRITE_FAILURE, MYF(0));
 		break;
 	case DB_TOO_BIG_INDEX_COL:
 		my_error(ER_INDEX_COLUMN_TOO_LONG, MYF(0),
@@ -346,12 +343,12 @@ my_error_innodb(
 		/* TODO: report the row, as we do for DB_DUPLICATE_KEY */
 		my_error(ER_INVALID_USE_OF_NULL, MYF(0));
 		break;
-	case DB_TABLESPACE_EXISTS:
-		my_error(ER_TABLESPACE_EXISTS, MYF(0), table);
-		break;
 	case DB_CANT_CREATE_GEOMETRY_OBJECT:
 		my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, MYF(0));
 		break;
+	case DB_TABLESPACE_EXISTS:
+		my_error(ER_TABLESPACE_EXISTS, MYF(0), table);
+		break;
 
 #ifdef UNIV_DEBUG
 	case DB_SUCCESS:
@@ -457,6 +454,8 @@ innobase_need_rebuild(
 
 	return(!!(ha_alter_info->handler_flags & INNOBASE_ALTER_REBUILD));
 }
+
+#ifdef MYSQL_VIRTUAL_COLUMNS
 /** Check if virtual column in old and new table are in order, excluding
 those dropped column. This is needed because when we drop a virtual column,
 ALTER_VIRTUAL_COLUMN_ORDER is also turned on, so we can't decide if this
@@ -475,20 +474,49 @@ check_v_col_in_order(
 {
 	ulint	j = 0;
 
+	/* We don't support any adding new virtual column before
+	existed virtual column. */
+	if (ha_alter_info->handler_flags
+              & Alter_inplace_info::ADD_VIRTUAL_COLUMN) {
+		bool			has_new = false;
+
+		List_iterator_fast<Create_field> cf_it(
+			ha_alter_info->alter_info->create_list);
+
+		cf_it.rewind();
+
+		while (const Create_field* new_field = cf_it++) {
+			if (!new_field->is_virtual_gcol()) {
+				continue;
+			}
+
+			/* Found a new added virtual column. */
+			if (!new_field->field) {
+				has_new = true;
+				continue;
+			}
+
+			/* If there's any old virtual column
+			after the new added virtual column,
+			order must be changed. */
+			if (has_new) {
+				return(false);
+			}
+		}
+	}
+
 	/* directly return true if ALTER_VIRTUAL_COLUMN_ORDER is not on */
-	/* JAN: TODO: MySQL 5.7
 	if (!(ha_alter_info->handler_flags
               & Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER)) {
 		return(true);
 	}
-	*/
 
 	for (ulint i = 0; i < table->s->fields; i++) {
 		Field*		field = table->s->field[i];
 		bool		dropped = false;
 		Alter_drop*	drop;
 
-		if (field->stored_in_db()) {
+		if (field->stored_in_db) {
 			continue;
 		}
 
@@ -513,9 +541,9 @@ check_v_col_in_order(
 		/* Now check if the next virtual column in altered table
 		matches this column */
 		while (j < altered_table->s->fields) {
-			Field*  new_field = altered_table->s->field[j];
+			 Field*  new_field = altered_table->s->field[j];
 
-			if (new_field->stored_in_db()) {
+			if (new_field->stored_in_db) {
 				j++;
 				continue;
 			}
@@ -541,6 +569,7 @@ check_v_col_in_order(
 
 	return(true);
 }
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 
 /** Check if InnoDB supports a particular alter table in-place
 @param altered_table TABLE object for new version of table.
@@ -569,9 +598,7 @@ ha_innobase::check_if_supported_inplace_alter(
 	    || srv_sys_space.created_new_raw()
 	    || srv_force_recovery) {
 		ha_alter_info->unsupported_reason = (srv_force_recovery)?
-			innobase_get_err_msg(ER_READ_ONLY_MODE):
-			// JAN: TODO: MySQL 5.7
-			//			innobase_get_err_msg(ER_INNODB_FORCED_RECOVERY):
+			innobase_get_err_msg(ER_INNODB_FORCED_RECOVERY):
 			innobase_get_err_msg(ER_READ_ONLY_MODE);
 
 		DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
@@ -587,6 +614,21 @@ ha_innobase::check_if_supported_inplace_alter(
 		DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
 	}
 
+#ifdef MYSQL_ENCRYPTION
+	/* We don't support change encryption attribute with
+	inplace algorithm. */
+	char*	old_encryption = this->table->s->encrypt_type.str;
+	char*	new_encryption = altered_table->s->encrypt_type.str;
+
+	if (Encryption::is_none(old_encryption)
+	    != Encryption::is_none(new_encryption)) {
+		ha_alter_info->unsupported_reason =
+			innobase_get_err_msg(
+				ER_UNSUPPORTED_ALTER_ENCRYPTION_INPLACE);
+		DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+	}
+#endif /* MYSQL_ENCRYPTION */
+
 	update_thd();
 	trx_search_latch_release_if_reserved(m_prebuilt->trx);
 
@@ -618,13 +660,14 @@ ha_innobase::check_if_supported_inplace_alter(
 		| INNOBASE_ALTER_NOREBUILD
 		| INNOBASE_ALTER_REBUILD)) {
 
-		/* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_STORED_COLUMNS
 		if (ha_alter_info->handler_flags
 		    & Alter_inplace_info::ALTER_STORED_COLUMN_TYPE) {
 			ha_alter_info->unsupported_reason = innobase_get_err_msg(
 				ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE);
 		}
-		*/
+#endif
+
 		DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
 	}
 
@@ -659,18 +702,6 @@ ha_innobase::check_if_supported_inplace_alter(
 		DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
 	}
 
-	/* InnoDB cannot IGNORE when creating unique indexes. IGNORE
-	should silently delete some duplicate rows. Our inplace_alter
-	code will not delete anything from existing indexes. */
-	if (ha_alter_info->ignore
-	    && (ha_alter_info->handler_flags
-		& (Alter_inplace_info::ADD_PK_INDEX
-		   | Alter_inplace_info::ADD_UNIQUE_INDEX))) {
-		ha_alter_info->unsupported_reason = innobase_get_err_msg(
-			ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_IGNORE);
-		DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
-	}
-
 	/* DROP PRIMARY KEY is only allowed in combination with ADD
 	PRIMARY KEY. */
 	if ((ha_alter_info->handler_flags
@@ -775,30 +806,31 @@ ha_innobase::check_if_supported_inplace_alter(
 		DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
 	}
 
+#ifdef MYSQL_VIRTUAL_COLUMNS
+	// JAN: TODO: MySQL 5.7 Virtual columns
 	/* If there is add or drop virtual columns, we will support operations
 	with these 2 options alone with inplace interface for now */
-	/* JAN: TODO: MySQL 5.7
+
 	if (ha_alter_info->handler_flags
 	    & (Alter_inplace_info::ADD_VIRTUAL_COLUMN
 	       | Alter_inplace_info::DROP_VIRTUAL_COLUMN
 	       | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER)) {
-		ulint	flags = ha_alter_info->handler_flags;
-	*/
+		ulonglong flags = ha_alter_info->handler_flags;
+
 		/* TODO: uncomment the flags below, once we start to
 		support them */
-	/*
+
 		flags &= ~(Alter_inplace_info::ADD_VIRTUAL_COLUMN
 			   | Alter_inplace_info::DROP_VIRTUAL_COLUMN
 			   | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER
-	*/
-			   /*
+		           | Alter_inplace_info::ALTER_VIRTUAL_GCOL_EXPR
+		/*
 			   | Alter_inplace_info::ALTER_STORED_COLUMN_ORDER
-			   | Alter_inplace_info::ADD_STORED_COLUMN
+			   | Alter_inplace_info::ADD_STORED_BASE_COLUMN
 			   | Alter_inplace_info::DROP_STORED_COLUMN
 			   | Alter_inplace_info::ALTER_STORED_COLUMN_ORDER
 			   | Alter_inplace_info::ADD_UNIQUE_INDEX
-			   */
-	/*
+		*/
 			   | Alter_inplace_info::ADD_INDEX
 			   | Alter_inplace_info::DROP_INDEX);
 
@@ -812,22 +844,10 @@ ha_innobase::check_if_supported_inplace_alter(
 				ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN);
 			DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
 		}
-	*/
-		/* Do not support inplace alter table drop virtual
-		columns and add index together yet */
-	/*
-		if ((ha_alter_info->handler_flags
-		     & Alter_inplace_info::ADD_INDEX)
-		    && (ha_alter_info->handler_flags
-			& Alter_inplace_info::DROP_VIRTUAL_COLUMN)) {
 
-			ha_alter_info->unsupported_reason =
-				innobase_get_err_msg(
-				ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN);
-			DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
-		}
+		add_drop_v_cols = true;
 	}
-	*/
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 
 	/* We should be able to do the operation in-place.
 	See if we can do it online (LOCK=NONE). */
@@ -842,6 +862,19 @@ ha_innobase::check_if_supported_inplace_alter(
 		     + ha_alter_info->key_count;
 	     new_key++) {
 
+#ifdef MYSQL_VIRTUAL_COLUMNS
+		/* Do not support adding/droping a vritual column, while
+		there is a table rebuild caused by adding a new FTS_DOC_ID */
+		if ((new_key->flags & HA_FULLTEXT) && add_drop_v_cols
+		    && !DICT_TF2_FLAG_IS_SET(m_prebuilt->table,
+					     DICT_TF2_FTS_HAS_DOC_ID)) {
+			ha_alter_info->unsupported_reason =
+				innobase_get_err_msg(
+				ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN);
+			DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+		}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
 		for (KEY_PART_INFO* key_part = new_key->key_part;
 		     key_part < new_key->key_part + new_key->user_defined_key_parts;
 		     key_part++) {
@@ -861,6 +894,7 @@ ha_innobase::check_if_supported_inplace_alter(
 
 			key_part->field = altered_table->field[
 				key_part->fieldnr];
+
 			/* In some special cases InnoDB emits "false"
 			duplicate key errors with NULL key values. Let
 			us play safe and ensure that we can correctly
@@ -905,9 +939,26 @@ ha_innobase::check_if_supported_inplace_alter(
 				online = false;
 			}
 
-			if (innobase_is_v_fld(key_part->field)) {
+#ifdef MYSQL_VIRTUAL_COLUMNS
+			if (key_part->field->is_virtual_gcol()) {
+				/* Do not support adding index on newly added
+				virtual column, while there is also a drop
+				virtual column in the same clause */
+				if (ha_alter_info->handler_flags
+				    & Alter_inplace_info::DROP_VIRTUAL_COLUMN) {
+					ha_alter_info->unsupported_reason =
+						innobase_get_err_msg(
+							ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN);
+
+					DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+				}
+
+				ha_alter_info->unsupported_reason =
+					innobase_get_err_msg(
+						ER_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN);
 				online = false;
 			}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 		}
 	}
 
@@ -916,19 +967,15 @@ ha_innobase::check_if_supported_inplace_alter(
 	DBUG_ASSERT(!m_prebuilt->table->fts || m_prebuilt->table->fts->doc_col
 		    < dict_table_get_n_user_cols(m_prebuilt->table));
 
-	/*
+#ifdef MYSQL_SPATIAL_INDEX
 	if (ha_alter_info->handler_flags
 	    & Alter_inplace_info::ADD_SPATIAL_INDEX) {
+		ha_alter_info->unsupported_reason = innobase_get_err_msg(
+			ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS);
 		online = false;
 	}
+#endif
 
-	if ((ha_alter_info->handler_flags
-	     & Alter_inplace_info::ADD_VIRTUAL_COLUMN)
-	    && (ha_alter_info->handler_flags
-	        & Alter_inplace_info::ADD_INDEX)) {
-		online = false;
-	}
-	*/
 	if (m_prebuilt->table->fts
 	    && innobase_fulltext_exist(altered_table)) {
 		/* FULLTEXT indexes are supposed to remain. */
@@ -987,17 +1034,20 @@ ha_innobase::check_if_supported_inplace_alter(
 			DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
 		}
 
-		/*
 		if (innobase_spatial_exist(altered_table)) {
+#ifdef MYSQL_SPATIAL_INDEX
 			ha_alter_info->unsupported_reason =
 				innobase_get_err_msg(
 				ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS);
+#endif
+			ha_alter_info->unsupported_reason = innobase_get_err_msg(
+				ER_INNODB_FT_LIMIT);
+			DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
 		} else {
-		*/
 			ha_alter_info->unsupported_reason =
 				innobase_get_err_msg(
 				ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS);
-			//}
+		}
 	} else if ((ha_alter_info->handler_flags
 		    & Alter_inplace_info::ADD_INDEX)) {
 		/* Building a full-text index requires a lock.
@@ -1306,27 +1356,101 @@ innobase_find_fk_index(
 	return(NULL);
 }
 
-/*************************************************************//**
-Create InnoDB foreign key structure from MySQL alter_info
+#ifdef MYSQL_STORED_COLUMNS
+
+/** Check whether given column is a base of stored column.
+ at param[in]	col_name	column name
+ at param[in]	table		table
+ at param[in]	s_cols		list of stored columns
+ at return true if the given column is a base of stored column,else false. */
+static
+bool
+innobase_col_check_fk(
+	const char*		col_name,
+	const dict_table_t*	table,
+	dict_s_col_list*	s_cols)
+{
+	dict_s_col_list::const_iterator	it;
+
+	for (it = s_cols->begin();
+	     it != s_cols->end(); ++it) {
+		dict_s_col_t	s_col = *it;
+
+		for (ulint j = 0; j < s_col.num_base; j++) {
+			if (strcmp(col_name, dict_table_get_col_name(
+						table,
+						s_col.base_col[j]->ind)) == 0) {
+				return(true);
+			}
+		}
+	}
+
+	return(false);
+}
+
+/** Check whether the foreign key constraint is on base of any stored columns.
+ at param[in]	foreign	Foriegn key constraing information
+ at param[in]	table	table to which the foreign key objects
+to be added
+ at param[in]	s_cols	list of stored column information in the table.
+ at return true if yes, otherwise false. */
+static
+bool
+innobase_check_fk_stored(
+	const dict_foreign_t*	foreign,
+	const dict_table_t*	table,
+	dict_s_col_list*	s_cols)
+{
+	ulint	type = foreign->type;
+
+	type &= ~(DICT_FOREIGN_ON_DELETE_NO_ACTION
+		  | DICT_FOREIGN_ON_UPDATE_NO_ACTION);
+
+	if (type == 0 || s_cols == NULL) {
+		return(false);
+	}
+
+	for (ulint i = 0; i < foreign->n_fields; i++) {
+		if (innobase_col_check_fk(
+			foreign->foreign_col_names[i], table, s_cols)) {
+			return(true);
+		}
+	}
+
+	return(false);
+}
+#endif /* MYSQL_STORED_COLUMNS */
+
+/** Create InnoDB foreign key structure from MySQL alter_info
+ at param[in]	ha_alter_info	alter table info
+ at param[in]	table_share	TABLE_SHARE
+ at param[in]	table		table object
+ at param[in]	col_names	column names, or NULL to use
+table->col_names
+ at param[in]	drop_index	indexes to be dropped
+ at param[in]	n_drop_index	size of drop_index
+ at param[out]	add_fk		foreign constraint added
+ at param[out]	n_add_fk	number of foreign constraints
+added
+ at param[in]	trx		user transaction
+ at param[in]	s_cols		list of stored column information
 @retval true if successful
 @retval false on error (will call my_error()) */
 static MY_ATTRIBUTE((nonnull(1,2,3,7,8), warn_unused_result))
 bool
 innobase_get_foreign_key_info(
-/*==========================*/
 	Alter_inplace_info*
-			ha_alter_info,	/*!< in: alter table info */
+			ha_alter_info,
 	const TABLE_SHARE*
-			table_share,	/*!< in: the TABLE_SHARE */
-	dict_table_t*	table,		/*!< in: table */
-	const char**	col_names,	/*!< in: column names, or NULL
-					to use table->col_names */
-	dict_index_t**	drop_index,	/*!< in: indexes to be dropped */
-	ulint		n_drop_index,	/*!< in: size of drop_index[] */
-	dict_foreign_t**add_fk,		/*!< out: foreign constraint added */
-	ulint*		n_add_fk,	/*!< out: number of foreign
-					constraints added */
-	const trx_t*	trx)		/*!< in: user transaction */
+			table_share,
+	dict_table_t*	table,
+	const char**	col_names,
+	dict_index_t**	drop_index,
+	ulint		n_drop_index,
+	dict_foreign_t**add_fk,
+	ulint*		n_add_fk,
+	const trx_t*	trx,
+	dict_s_col_list*s_cols)
 {
 	Key*		key;
 	Foreign_key*	fk_key;
@@ -1343,8 +1467,6 @@ innobase_get_foreign_key_info(
 
 	while ((key=key_iterator++)) {
 		if (key->type != Key::FOREIGN_KEY) {
-			// JAN: TODO: ? 
-			//		if (key->type != KEYTYPE_FOREIGN) {
 			continue;
 		}
 
@@ -1413,7 +1535,7 @@ innobase_get_foreign_key_info(
 		add_fk[num_fk] = dict_mem_foreign_create();
 
 #ifndef _WIN32
-		if(fk_key->ref_db.str) {
+		if (fk_key->ref_db.str) {
 			tablename_to_filename(fk_key->ref_db.str, db_name,
 					      MAX_DATABASE_NAME_LEN);
 			db_namep = db_name;
@@ -1545,6 +1667,14 @@ innobase_get_foreign_key_info(
 			goto err_exit;
 		}
 
+#ifdef MYSQL_STORED_BASE_COLUMNS
+		if (innobase_check_fk_stored(
+			add_fk[num_fk], table, s_cols)) {
+			my_error(ER_CANNOT_ADD_FOREIGN_BASE_COL_STORED, MYF(0));
+			goto err_exit;
+		}
+#endif
+
 		num_fk++;
 	}
 
@@ -1665,7 +1795,7 @@ innobase_rec_to_mysql(
 					rec, index, ...) */
 {
 	uint	n_fields	= table->s->stored_fields;
-        uint    sql_idx         = 0;
+	uint	sql_idx		= 0;
 
 	ut_ad(n_fields == dict_table_get_n_user_cols(index->table)
 	      - !!(DICT_TF2_FLAG_IS_SET(index->table,
@@ -1678,8 +1808,9 @@ innobase_rec_to_mysql(
 		const uchar*	ifield;
 		ulint prefix_col;
 
-                while (!((field= table->field[sql_idx])->stored_in_db()))
-                          sql_idx++;
+		while (!((field= table->field[sql_idx])->stored_in_db())) {
+			sql_idx++;
+		}
 
 		field->reset();
 
@@ -1720,8 +1851,8 @@ innobase_fields_to_mysql(
 	const dfield_t*		fields)	/*!< in: InnoDB index fields */
 {
 	uint	n_fields	= table->s->stored_fields;
-        uint    sql_idx         = 0;
-	ulint	num_v = 0;
+	uint	sql_idx		= 0;
+	ulint	num_v 		= 0;
 
 	ut_ad(n_fields == dict_table_get_n_user_cols(index->table)
 	      + dict_table_get_n_v_cols(index->table)
@@ -1734,8 +1865,9 @@ innobase_fields_to_mysql(
 		ulint		col_n;
 		ulint		prefix_col;
 
-                while (!((field= table->field[sql_idx])->stored_in_db()))
-                          sql_idx++;
+		while (!((field= table->field[sql_idx])->stored_in_db())) {
+			sql_idx++;
+		}
 
 		field->reset();
 
@@ -1778,8 +1910,9 @@ innobase_row_to_mysql(
 	const dict_table_t*	itab,	/*!< in: InnoDB table */
 	const dtuple_t*		row)	/*!< in: InnoDB row */
 {
-	uint  n_fields	= table->s->stored_fields;
-        uint  sql_idx   = 0;
+	uint	n_fields	= table->s->stored_fields;
+	uint	sql_idx		= 0;
+	uint	num_v		= 0;
 
 	/* The InnoDB row may contain an extra FTS_DOC_ID column at the end. */
 	ut_ad(row->n_fields == dict_table_get_n_cols(itab));
@@ -1789,20 +1922,29 @@ innobase_row_to_mysql(
 
 	for (uint i = 0; i < n_fields; i++, sql_idx++) {
 		Field*          field;
-		const dfield_t*	df	= dtuple_get_nth_field(row, i);
 
-                while (!((field= table->field[sql_idx])->stored_in_db()))
-                          sql_idx++;
+		while (!((field= table->field[sql_idx])->stored_in_db())) {
+			sql_idx++;
+		}
 
 		field->reset();
 
+		if (innobase_is_v_fld(field)) {
+			/* Virtual column are not stored in InnoDB table, so
+			skip it */
+			num_v++;
+			continue;
+		}
+
+		const dfield_t*	df	= dtuple_get_nth_field(row, i - num_v);
+
 		if (dfield_is_ext(df) || dfield_is_null(df)) {
 			field->set_null();
 		} else {
 			field->set_notnull();
 
 			innobase_col_to_mysql(
-				dict_table_get_nth_col(itab, i),
+				dict_table_get_nth_col(itab, i - num_v),
 				static_cast<const uchar*>(dfield_get_data(df)),
 				dfield_get_len(df), field);
 		}
@@ -1894,6 +2036,7 @@ innobase_check_index_keys(
 				}
 			}
 
+#ifdef MYSQL_RENAME_INDEX
 			/* If a key by the same name is being created and
 			renamed, the name clash is OK. E.g.
 			ALTER TABLE t ADD INDEX i (col), RENAME INDEX i TO x
@@ -1901,7 +2044,6 @@ innobase_check_index_keys(
 			In this case we:
 			1. rename the existing index from "i" to "x"
 			2. add the new index "i" */
-			/* JAN: TODO: MySQL 5.7
 			for (uint i = 0; i < info->index_rename_count; i++) {
 				const KEY_PAIR*	pair
 					= &info->index_rename_buffer[i];
@@ -1910,7 +2052,8 @@ innobase_check_index_keys(
 					goto name_ok;
 				}
 			}
-			*/
+#endif /* MYSQL_RENAME_INDEX */
+
 			my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key.name);
 
 			return(ER_WRONG_NAME_FOR_INDEX);
@@ -1987,7 +2130,6 @@ innobase_check_index_keys(
 static
 void
 innobase_create_index_field_def(
-/*============================*/
 	const TABLE*		altered_table,
 	const KEY_PART_INFO*	key_part,
 	index_field_t*		index_field,
@@ -2024,19 +2166,21 @@ innobase_create_index_field_def(
 	col_type = get_innobase_type_from_mysql_type(
 		&is_unsigned, field);
 
-	// JAN: TODO: MySQL 5.7 Virtual columns
-	//if (!field->stored_in_db && field->gcol_info) {
-	// if (!field->stored_in_db() && false) {
-	//	index_field->is_v_col = true;
-	//	index_field->col_no = num_v;
-	// } else {
-	//      index_field->is_v_col = false;
-	//	index_field->col_no = key_part->fieldnr - num_v;
-	//}
-
+#ifdef MYSQL_VIRTUAL_COLUMNS
+	if (!field->stored_in_db && field->gcol_info) {
+		if (!field->stored_in_db && false) {
+			index_field->is_v_col = true;
+			index_field->col_no = num_v;
+		} else {
+			index_field->is_v_col = false;
+			index_field->col_no = key_part->fieldnr - num_v;
+		}
+	}
+#else
 	index_field->is_v_col = false;
 	index_field->col_no = key_part->fieldnr - num_m_v;
 	index_field->col_name = altered_table ? field->field_name : fields[key_part->fieldnr]->field_name;
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 
 	if (DATA_LARGE_MTYPE(col_type)
 	    || (key_part->length < field->pack_length()
@@ -2062,23 +2206,17 @@ index on the table
 @param[in]	key_clustered		true if this is the new clustered index
 @param[out]	index			index definition
 @param[in]	heap			heap where memory is allocated */
+static MY_ATTRIBUTE((nonnull))
 void
 innobase_create_index_def(
-/*======================*/
-	const TABLE*		altered_table,	/*!< in: MySQL table that is
-						being altered */
-	const KEY*		keys,		/*!< in: key definitions */
-	ulint			key_number,	/*!< in: MySQL key number */
-	bool			new_clustered,	/*!< in: true if generating
-						a new clustered index
-						on the table */
-	bool			key_clustered,	/*!< in: true if this is
-						the new clustered index */
-	index_def_t*		index,		/*!< out: index definition */
-	mem_heap_t*		heap,		/*!< in: heap where memory
-						is allocated */
-	const Field**		fields)		/*!< in: MySQL table fields
-						*/
+	const TABLE*		altered_table,
+	const KEY*		keys,
+	ulint			key_number,
+	bool			new_clustered,
+	bool			key_clustered,
+	index_def_t*		index,
+	mem_heap_t*		heap,
+	const Field**		fields)
 {
 	const KEY*	key = &keys[key_number];
 	ulint		i;
@@ -2110,10 +2248,10 @@ innobase_create_index_def(
 				  | HA_BINARY_PACK_KEY)));
 		index->ind_type = DICT_FTS;
 
-		/* Set plugin parser */
+#ifdef MYSQL_FTS_PARSER
 		/* Note: key->parser is only parser name,
 			 we need to get parser from altered_table instead */
-		/* JAN: TODO: MySQL FTS Parser
+
 		if (key->flags & HA_USES_PARSER) {
 			for (ulint j = 0; j < altered_table->s->keys; j++) {
 				if (ut_strcmp(altered_table->key_info[j].name,
@@ -2141,8 +2279,7 @@ innobase_create_index_def(
 				index->parser = &fts_default_parser;);
 			ut_ad(index->parser);
 		}
-		*/
-		index->parser = &fts_default_parser;
+#endif /* MYSQL_FTS_PARSER */
 	} else if (key->flags & HA_SPATIAL) {
 		DBUG_ASSERT(!(key->flags & HA_NOSAME));
 		index->ind_type = DICT_SPATIAL;
@@ -2159,20 +2296,22 @@ innobase_create_index_def(
 		index->fields[0].col_no = key->key_part[0].fieldnr - num_v;
 		index->fields[0].prefix_len = 0;
 		index->fields[0].is_v_col = false;
-		/* JAN: TODO: MySQL 5.7 Virtual columns & spatial indexes
-		if (!key->key_part[0].field->stored_in_db()
+
+ #ifdef MYSQL_VIRTUAL_COLUMNS
+		if (!key->key_part[0].field->stored_in_db
 		    && key->key_part[0].field->gcol_info) {
-		*/
+
 			/* Currently, the spatial index cannot be created
 			on virtual columns. It is blocked in server
 			layer */
-		/*
+
 			ut_ad(0);
 			index->fields[0].is_v_col = true;
 		} else {
-		*/
+
 			index->fields[0].is_v_col = false;
-		//}
+		}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 	} else {
 		index->ind_type = (key->flags & HA_NOSAME) ? DICT_UNIQUE : 0;
 	}
@@ -2213,7 +2352,7 @@ innobase_fts_check_doc_id_col(
 	*fts_doc_col_no = ULINT_UNDEFINED;
 
 	const uint n_cols = altered_table->s->stored_fields;
-        uint sql_idx = 0;
+	uint sql_idx = 0;
 	ulint	i;
 
 	*num_v = 0;
@@ -2566,7 +2705,7 @@ innobase_create_key_defs(
 				    NULL, altered_table,
 				    &fts_doc_id_col, &num_v)) {
 				fts_doc_id_col =
-                                  altered_table->s->stored_fields;
+					altered_table->s->stored_fields;
 				add_fts_doc_id = true;
 			}
 
@@ -2743,7 +2882,7 @@ online_retry_drop_indexes_with_trx(
 @param drop_fk constraints being dropped
 @param n_drop_fk number of constraints that are being dropped
 @return whether the constraint is being dropped */
-inline MY_ATTRIBUTE((pure, nonnull, warn_unused_result))
+inline MY_ATTRIBUTE((warn_unused_result))
 bool
 innobase_dropping_foreign(
 /*======================*/
@@ -2770,7 +2909,7 @@ column that is being dropped or modified to NOT NULL.
 @retval true Not allowed (will call my_error())
 @retval false Allowed
 */
-static MY_ATTRIBUTE((pure, nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
 bool
 innobase_check_foreigns_low(
 /*========================*/
@@ -2870,7 +3009,7 @@ column that is being dropped or modified to NOT NULL.
 @retval true Not allowed (will call my_error())
 @retval false Allowed
 */
-static MY_ATTRIBUTE((pure, nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
 bool
 innobase_check_foreigns(
 /*====================*/
@@ -2996,7 +3135,7 @@ innobase_build_col_map(
 	dtuple_t*		add_cols,
 	mem_heap_t*		heap)
 {
-        uint old_i, old_innobase_i;
+	uint old_i, old_innobase_i;
 	DBUG_ENTER("innobase_build_col_map");
 	DBUG_ASSERT(altered_table != table);
 	DBUG_ASSERT(new_table != old_table);
@@ -3023,7 +3162,7 @@ innobase_build_col_map(
 
 	/* Any dropped columns will map to ULINT_UNDEFINED. */
 	for (old_innobase_i = 0;
-             old_innobase_i + DATA_N_SYS_COLS < old_table->n_cols;
+	     old_innobase_i + DATA_N_SYS_COLS < old_table->n_cols;
 	     old_innobase_i++) {
 		col_map[old_innobase_i] = ULINT_UNDEFINED;
 	}
@@ -3071,7 +3210,7 @@ innobase_build_col_map(
 				col_map[old_innobase_i] = i;
 				goto found_col;
 			}
-                        old_innobase_i++;
+			old_innobase_i++;
 		}
 
 		ut_ad(!is_v);
@@ -3113,8 +3252,9 @@ innobase_build_col_map(
 				    + DATA_N_SYS_COLS + 1
 				    == new_table->n_cols);
 			col_map[i] = altered_table->s->stored_fields;
-			col_map[i] = altered_table->s->fields
+			/* col_map[i] = altered_table->s->fields
 				     - new_table->n_v_cols;
+			*/
 		} else {
 			DBUG_ASSERT(!DICT_TF2_FLAG_IS_SET(
 					    new_table,
@@ -3303,7 +3443,7 @@ PK columns follows rule(2).
 @param[in]	new_clust_index index to be compared
 @retval true if both indexes have same order.
 @retval false. */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
 bool
 innobase_pk_order_preserved(
 	const ulint*		col_map,
@@ -3530,6 +3670,8 @@ innobase_check_gis_columns(
 	DBUG_RETURN(DB_SUCCESS);
 }
 
+#ifdef MYSQL_VIRTUAL_COLUMNS
+
 /** Collect virtual column info for its addition
 @param[in] ha_alter_info	Data used during in-place alter
 @param[in] altered_table	MySQL table that is being altered to
@@ -3590,14 +3732,12 @@ prepare_inplace_add_virtual(
 
 		field =  altered_table->field[i - 1];
 
-		ulint           col_type
-                                = get_innobase_type_from_mysql_type(
-                                        &is_unsigned, field);
+		ulint	col_type
+				= get_innobase_type_from_mysql_type(
+					&is_unsigned, field);
+
 
-		/* JAN: TODO: MySQL 5.7
 		if (!field->gcol_info || field->stored_in_db) {
-		*/
-		if (field->stored_in_db()) {
 			my_error(ER_WRONG_KEY_COLUMN, MYF(0),
 				 field->field_name);
 			return(true);
@@ -3740,10 +3880,8 @@ prepare_inplace_drop_virtual(
                                 = get_innobase_type_from_mysql_type(
                                         &is_unsigned, field);
 
-		/* JAN: TODO: MySQL 5.7
+
 		if (!field->gcol_info || field->stored_in_db) {
-		*/
-		if (field->stored_in_db()) {
 			my_error(ER_WRONG_KEY_COLUMN, MYF(0),
 				 field->field_name);
 			return(true);
@@ -4225,6 +4363,90 @@ innobase_drop_virtual_try(
 	return(false);
 }
 
+/** Adjust the create index column number from "New table" to
+"old InnoDB table" while we are doing dropping virtual column. Since we do
+not create separate new table for the dropping/adding virtual columns.
+To correctly find the indexed column, we will need to find its col_no
+in the "Old Table", not the "New table".
+ at param[in]	ha_alter_info	Data used during in-place alter
+ at param[in]	old_table	MySQL table as it is before the ALTER operation
+ at param[in]	num_v_dropped	number of virtual column dropped
+ at param[in,out]	index_def	index definition */
+static
+void
+innodb_v_adjust_idx_col(
+	const Alter_inplace_info*	ha_alter_info,
+	const TABLE*			old_table,
+	ulint				num_v_dropped,
+	index_def_t*			index_def)
+{
+	List_iterator_fast<Create_field> cf_it(
+		ha_alter_info->alter_info->create_list);
+	for (ulint i = 0; i < index_def->n_fields; i++) {
+#ifdef UNIV_DEBUG
+		bool	col_found = false;
+#endif /* UNIV_DEBUG */
+		ulint	num_v = 0;
+
+		index_field_t*	index_field = &index_def->fields[i];
+
+		/* Only adjust virtual column col_no, since non-virtual
+		column position (in non-vcol list) won't change unless
+		table rebuild */
+		if (!index_field->is_v_col) {
+			continue;
+		}
+
+		const Field*	field = NULL;
+
+		cf_it.rewind();
+
+		/* Found the field in the new table */
+		while (const Create_field* new_field = cf_it++) {
+			if (!new_field->is_virtual_gcol()) {
+				continue;
+			}
+
+			field = new_field->field;
+
+			if (num_v == index_field->col_no) {
+				break;
+			}
+			num_v++;
+		}
+
+		if (!field) {
+			/* this means the field is a newly added field, this
+			should have been blocked when we drop virtual column
+			at the same time */
+			ut_ad(num_v_dropped > 0);
+			ut_a(0);
+		}
+
+		ut_ad(field->is_virtual_gcol());
+
+		num_v = 0;
+
+		/* Look for its position in old table */
+		for (uint old_i = 0; old_table->field[old_i]; old_i++) {
+			if (old_table->field[old_i] == field) {
+				/* Found it, adjust its col_no to its position
+				in old table */
+				index_def->fields[i].col_no = num_v;
+				ut_d(col_found = true);
+				break;
+			}
+
+			if (old_table->field[old_i]->is_virtual_gcol()) {
+				num_v++;
+			}
+		}
+
+		ut_ad(col_found);
+	}
+}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
 /** Update internal structures with concurrent writes blocked,
 while preparing ALTER TABLE.
 
@@ -4262,8 +4484,8 @@ prepare_inplace_alter_table_dict(
 	dict_index_t*		fts_index	= NULL;
 	ulint			new_clustered	= 0;
 	dberr_t			error;
+	const char*		punch_hole_warning = NULL;
 	ulint			num_fts_index;
-        uint			sql_idx;
 	dict_add_v_col_t*	add_v = NULL;
 	ha_innobase_inplace_ctx*ctx;
 
@@ -4288,7 +4510,7 @@ prepare_inplace_alter_table_dict(
 
 	trx_start_if_not_started_xa(ctx->prebuilt->trx, true);
 
-	/* JAN: TODO: MySQL 5.7 Virtual columns
+#ifdef MYSQL_VIRTUAL_COLUMNS
 	if (ha_alter_info->handler_flags
 	    & Alter_inplace_info::DROP_VIRTUAL_COLUMN) {
 		if (prepare_inplace_drop_virtual(
@@ -4303,10 +4525,10 @@ prepare_inplace_alter_table_dict(
 			    ha_alter_info, altered_table, old_table)) {
 			DBUG_RETURN(true);
 		}
-	*/
+
 		/* Need information for newly added virtual columns
 		for create index */
-	/*
+
 		if (ha_alter_info->handler_flags
 		    & Alter_inplace_info::ADD_INDEX) {
 			add_v = static_cast<dict_add_v_col_t*>(
@@ -4316,15 +4538,13 @@ prepare_inplace_alter_table_dict(
 			add_v->v_col_name = ctx->add_vcol_name;
 		}
 	}
-	*/
-	/*
 
-	JAN: TODO: MySQL 5.7 Virtual columns
-
-        There should be no order change for virtual columns coming in
+	/*
+	There should be no order change for virtual columns coming in
 	here
-	ut_ad(check_v_col_in_order(old_table, altered_table, ha_alter_info));
 	*/
+	ut_ad(check_v_col_in_order(old_table, altered_table, ha_alter_info));
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 
 	/* Create a background transaction for the operations on
 	the data dictionary tables. */
@@ -4339,9 +4559,8 @@ prepare_inplace_alter_table_dict(
 	ctx->num_to_add_index = ha_alter_info->index_add_count;
 
 	ut_ad(ctx->prebuilt->trx->mysql_thd != NULL);
-	/* const char*	path = thd_innodb_tmpdir(
+	const char*	path = thd_innodb_tmpdir(
 		ctx->prebuilt->trx->mysql_thd);
-	*/
 
 	index_defs = innobase_create_key_defs(
 		ctx->heap, ha_alter_info, altered_table, ctx->num_to_add_index,
@@ -4443,7 +4662,6 @@ prepare_inplace_alter_table_dict(
 		ulint		n_mv_cols = 0;
 		dtuple_t*	add_cols;
 		ulint		space_id = 0;
-		ulint		z = 0;
 		ulint		key_id = FIL_DEFAULT_ENCRYPTION_KEY;
 		fil_encryption_t mode = FIL_SPACE_ENCRYPTION_DEFAULT;
 		const char*	compression=NULL;
@@ -4500,8 +4718,9 @@ prepare_inplace_alter_table_dict(
 		/* Use the old tablespace unless the tablespace
 		is changing. */
 		if (DICT_TF_HAS_SHARED_SPACE(user_table->flags)
-		    && (0 == strcmp(ha_alter_info->create_info->tablespace,
-				    user_table->tablespace))) {
+		    && (ha_alter_info->create_info->tablespace == NULL
+			|| (0 == strcmp(ha_alter_info->create_info->tablespace,
+					user_table->tablespace)))) {
 			space_id = user_table->space;
 		} else if (tablespace_is_shared_space(
 				ha_alter_info->create_info)) {
@@ -4532,9 +4751,9 @@ prepare_inplace_alter_table_dict(
 			ulint		charset_no;
 			ulint		col_len;
 
-                        while (!((field= altered_table->field[sql_idx])->
-					stored_in_db()))
-                          sql_idx++;
+			while (!((field= altered_table->field[sql_idx])->stored_in_db())) {
+				sql_idx++;
+			}
 
 			ulint		field_type = (ulint) field->type();
 			bool		is_virtual = innobase_is_v_fld(field);
@@ -4607,7 +4826,7 @@ prepare_inplace_alter_table_dict(
 			}
 
 			if (is_virtual) {
-				/* JAN: TODO: MySQL 5.7 virtual columns
+#ifdef MYSQL_VIRTUAL_COLUMNS
 				dict_mem_table_add_v_col(
 					ctx->new_table, ctx->heap,
 					field->field_name,
@@ -4617,7 +4836,7 @@ prepare_inplace_alter_table_dict(
 					| DATA_VIRTUAL,
 					col_len, i,
 					field->gcol_info->non_virtual_base_columns());
-				*/
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 			} else {
 				dict_mem_table_add_col(
 					ctx->new_table, ctx->heap,
@@ -4629,6 +4848,9 @@ prepare_inplace_alter_table_dict(
 			}
 		}
 
+#ifdef MYSQL_VIRTUAL_COLUMNS
+		ulint		z = 0;
+
 		if (n_v_cols) {
 			for (uint i = 0; i < altered_table->s->fields; i++) {
 				dict_v_col_t*	v_col;
@@ -4644,45 +4866,52 @@ prepare_inplace_alter_table_dict(
 					ctx->new_table, field, v_col);
 			}
 		}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 
 		if (add_fts_doc_id) {
 			fts_add_doc_id_column(ctx->new_table, ctx->heap);
 			ctx->new_table->fts->doc_col = fts_doc_id_col;
-			// JAN: TODO: MySQL 5.7 Virtual columns
-			// ut_ad(fts_doc_id_col
-			//      == altered_table->s->fields - n_v_cols);
-			// ut_ad(fts_doc_id_col == altered_table->s->stored_fields);
+			ut_ad(fts_doc_id_col
+			      == altered_table->s->stored_fields - n_v_cols);
+			ut_ad(fts_doc_id_col == altered_table->s->stored_fields);
 
 		} else if (ctx->new_table->fts) {
 			ctx->new_table->fts->doc_col = fts_doc_id_col;
 		}
 
-		/* JAN: TODO: MySQL 5.7 Compression
+#ifdef MYSQL_COMPRESSION
 		compression = ha_alter_info->create_info->compress.str;
 
-                if (Compression::validate(compression) != DB_SUCCESS) {
+		if (Compression::validate(compression) != DB_SUCCESS) {
 
-                        compression = NULL;
-                }
-		*/
+			compression = NULL;
+		}
+#endif /* MYSQL_COMPRESSION */
 
 		error = row_create_table_for_mysql(
 			ctx->new_table, compression, ctx->trx, false, mode, key_id);
 
+		punch_hole_warning =
+			(error == DB_IO_NO_PUNCH_HOLE_FS)
+			? "Punch hole is not supported by the file system"
+			: "Page Compression is not supported for this"
+			  " tablespace";
+
 		switch (error) {
 			dict_table_t*	temp_table;
 		case DB_IO_NO_PUNCH_HOLE_FS:
-
+		case DB_IO_NO_PUNCH_HOLE_TABLESPACE:
 			push_warning_printf(
 				ctx->prebuilt->trx->mysql_thd,
 				Sql_condition::WARN_LEVEL_WARN,
 				HA_ERR_UNSUPPORTED,
-				"XPunch hole not supported by the file system. "
-				"Compression disabled for '%s'",
+				"%s. Compression disabled for '%s'",
+				punch_hole_warning,
 				ctx->new_table->name.m_name);
 
 			error = DB_SUCCESS;
 
+
 		case DB_SUCCESS:
 			/* We need to bump up the table ref count and
 			before we can use it we need to open the
@@ -4755,12 +4984,23 @@ prepare_inplace_alter_table_dict(
 			}
 		}
 
-		if (!ctx->new_table->fts
-		    && innobase_fulltext_exist(altered_table)) {
-			ctx->new_table->fts = fts_create(
-				ctx->new_table);
-			ctx->new_table->fts->doc_col = fts_doc_id_col;
-		}
+		for (dict_index_t* index
+			     = dict_table_get_first_index(user_table);
+		     index != NULL;
+		     index = dict_table_get_next_index(index)) {
+			if (!index->to_be_dropped
+			    && dict_index_is_corrupted(index)) {
+				my_error(ER_CHECK_NO_SUCH_TABLE, MYF(0));
+				goto error_handled;
+			}
+		}
+
+		if (!ctx->new_table->fts
+		    && innobase_fulltext_exist(altered_table)) {
+			ctx->new_table->fts = fts_create(
+				ctx->new_table);
+			ctx->new_table->fts->doc_col = fts_doc_id_col;
+		}
 
 		/* Check if we need to update mtypes of legacy GIS columns.
 		This check is only needed when we don't have to rebuild
@@ -4784,6 +5024,15 @@ prepare_inplace_alter_table_dict(
 
 	for (ulint a = 0; a < ctx->num_to_add_index; a++) {
 
+#ifdef MYSQL_VIRTUAL_COLUMNS
+		if (index_defs[a].ind_type & DICT_VIRTUAL
+		    && ctx->num_to_drop_vcol > 0 && !new_clustered) {
+			innodb_v_adjust_idx_col(ha_alter_info, old_table,
+						ctx->num_to_drop_vcol,
+						&index_defs[a]);
+		}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
 		ctx->add_index[a] = row_merge_create_index(
 			ctx->trx, ctx->new_table,
 			&index_defs[a], add_v, ctx->col_names);
@@ -4828,8 +5077,8 @@ prepare_inplace_alter_table_dict(
 			rw_lock_x_lock(&ctx->add_index[a]->lock);
 
 			bool ok = row_log_allocate(ctx->add_index[a],
-						   NULL, true, NULL,
-						   NULL);
+						   NULL, true, NULL, NULL,
+						   path);
 			rw_lock_x_unlock(&ctx->add_index[a]->lock);
 
 			if (!ok) {
@@ -4863,7 +5112,7 @@ prepare_inplace_alter_table_dict(
 				clust_index, ctx->new_table,
 				!(ha_alter_info->handler_flags
 				  & Alter_inplace_info::ADD_PK_INDEX),
-				ctx->add_cols, ctx->col_map);
+				ctx->add_cols, ctx->col_map, path);
 			rw_lock_x_unlock(&clust_index->lock);
 
 			if (!ok) {
@@ -5166,6 +5415,7 @@ innobase_check_foreign_key_index(
 	return(false);
 }
 
+#ifdef MYSQL_RENAME_INDEX
 /**
 Rename a given index in the InnoDB data dictionary.
 
@@ -5175,7 +5425,7 @@ Rename a given index in the InnoDB data dictionary.
 
 @retval true Failure
 @retval false Success */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
 bool
 rename_index_in_data_dictionary(
 /*============================*/
@@ -5243,7 +5493,7 @@ rename
 
 @retval true Failure
 @retval false Success */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
 bool
 rename_indexes_in_data_dictionary(
 /*==============================*/
@@ -5253,7 +5503,6 @@ rename_indexes_in_data_dictionary(
 {
 	DBUG_ENTER("rename_indexes_in_data_dictionary");
 
-	/* JAN: TODO: MySQL 5.7
 	ut_ad(ctx->num_to_rename == ha_alter_info->index_rename_count);
 
 	for (ulint i = 0; i < ctx->num_to_rename; i++) {
@@ -5268,12 +5517,10 @@ rename_indexes_in_data_dictionary(
 		if (rename_index_in_data_dictionary(index,
 						    pair->new_key->name,
 						    trx)) {
-	*/
 			/* failed */
 			DBUG_RETURN(true);
-			/* }
+		}
 	}
-			*/
 
 	DBUG_RETURN(false);
 }
@@ -5322,6 +5569,7 @@ rename_index_in_cache(
 	DBUG_VOID_RETURN;
 }
 
+#
 /**
 Rename all indexes in data dictionary cache of a given table that are
 specified in ha_alter_info.
@@ -5338,7 +5586,6 @@ rename_indexes_in_cache(
 {
 	DBUG_ENTER("rename_indexes_in_cache");
 
-	/* JAN: TODO: MySQL 5.7 
 	ut_ad(ctx->num_to_rename == ha_alter_info->index_rename_count);
 
 	for (ulint i = 0; i < ctx->num_to_rename; i++) {
@@ -5351,10 +5598,60 @@ rename_indexes_in_cache(
 
 		rename_index_in_cache(index, pair->new_key->name);
 	}
-	*/
 
 	DBUG_VOID_RETURN;
 }
+#endif /* MYSQL_RENAME_INDEX */
+
+#ifdef MYSQL_STORED_COLUMNS
+/** Fill the stored column information in s_cols list.
+ at param[in]	altered_table	mysql table object
+ at param[in]	table		innodb table object
+ at param[out]	s_cols		list of stored column
+ at param[out]	s_heap		heap for storing stored
+column information. */
+static
+void
+alter_fill_stored_column(
+	const TABLE*		altered_table,
+	dict_table_t*		table,
+	dict_s_col_list**	s_cols,
+	mem_heap_t**		s_heap)
+{
+	ulint   n_cols = altered_table->s->fields;
+
+	for (ulint i = 0; i < n_cols; i++) {
+		Field* field = altered_table->field[i];
+		dict_s_col_t	s_col;
+
+		if (!innobase_is_s_fld(field)) {
+			continue;
+		}
+
+		ulint	num_base = field->gcol_info->non_virtual_base_columns();
+		dict_col_t*	col = dict_table_get_nth_col(table, i);
+
+		s_col.m_col = col;
+		s_col.s_pos = i;
+
+		if (*s_cols == NULL) {
+			*s_cols = UT_NEW_NOKEY(dict_s_col_list());
+			*s_heap = mem_heap_create(1000);
+		}
+
+		if (num_base != 0) {
+			s_col.base_col = static_cast<dict_col_t**>(mem_heap_zalloc(
+						*s_heap, num_base * sizeof(dict_col_t*)));
+		} else {
+			s_col.base_col = NULL;
+		}
+
+		s_col.num_base = num_base;
+		innodb_base_col_setup_for_stored(table, field, &s_col);
+		(*s_cols)->push_back(s_col);
+	}
+}
+#endif /* MYSQL_STORED_COLUMNS */
 
 /** Allows InnoDB to update internal structures with concurrent
 writes blocked (provided that check_if_supported_inplace_alter()
@@ -5394,6 +5691,8 @@ ha_innobase::prepare_inplace_alter_table(
 	bool		add_fts_doc_id		= false;
 	bool		add_fts_doc_id_idx	= false;
 	bool		add_fts_idx		= false;
+	dict_s_col_list*s_cols			= NULL;
+	mem_heap_t*	s_heap			= NULL;
 
 	DBUG_ENTER("prepare_inplace_alter_table");
 	DBUG_ASSERT(!ha_alter_info->handler_ctx);
@@ -5734,7 +6033,7 @@ ha_innobase::prepare_inplace_alter_table(
 			}
 
 			my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
-				 drop->type_name(), drop->name);
+				drop->type_name(), drop->name);
 			goto err_exit;
 found_fk:
 			continue;
@@ -5886,10 +6185,12 @@ ha_innobase::prepare_inplace_alter_table(
 	}
 
 	n_rename_index = 0;
-	// JAN: TODO: MySQL 5.7
-	//n_rename_index = ha_alter_info->index_rename_count;
 	rename_index = NULL;
 
+#ifdef MYSQL_RENAME_INDEX
+
+	n_rename_index = ha_alter_info->index_rename_count;
+
 	/* Create a list of dict_index_t objects that are to be renamed,
 	also checking for requests to rename nonexistent indexes. If
 	the table is going to be rebuilt (new_clustered == true in
@@ -5905,13 +6206,12 @@ ha_innobase::prepare_inplace_alter_table(
 			dict_index_t*	index = NULL;
 			const char*	old_name = NULL;
 
-			/* JAN: TODO: MySQL 5.7
 			const char*	old_name = ha_alter_info
 				->index_rename_buffer[i].old_key->name;
 
 			index = dict_table_get_index_on_name(indexed_table,
 							     old_name);
-			*/
+
 			if (index == NULL) {
 				my_error(ER_KEY_DOES_NOT_EXITS, MYF(0),
 					 old_name,
@@ -5922,6 +6222,7 @@ ha_innobase::prepare_inplace_alter_table(
 			rename_index[i] = index;
 		}
 	}
+#endif /* MYSQL_RENAME_INDEX */
 
 	n_add_fk = 0;
 
@@ -5929,6 +6230,10 @@ ha_innobase::prepare_inplace_alter_table(
 	    & Alter_inplace_info::ADD_FOREIGN_KEY) {
 		ut_ad(!m_prebuilt->trx->check_foreigns);
 
+#ifdef MYSQL_STORED_COLUMNS
+		alter_fill_stored_column(altered_table, m_prebuilt->table,
+					 &s_cols, &s_heap);
+#endif
 		add_fk = static_cast<dict_foreign_t**>(
 			mem_heap_zalloc(
 				heap,
@@ -5939,7 +6244,7 @@ ha_innobase::prepare_inplace_alter_table(
 			    ha_alter_info, table_share,
 			    m_prebuilt->table, col_names,
 			    drop_index, n_drop_index,
-			    add_fk, &n_add_fk, m_prebuilt->trx)) {
+			    add_fk, &n_add_fk, m_prebuilt->trx, s_cols)) {
 err_exit:
 			if (n_drop_index) {
 				row_mysql_lock_data_dictionary(m_prebuilt->trx);
@@ -5959,8 +6264,18 @@ ha_innobase::prepare_inplace_alter_table(
 				mem_heap_free(heap);
 			}
 
+			if (s_cols != NULL) {
+				UT_DELETE(s_cols);
+				mem_heap_free(s_heap);
+			}
+
 			goto err_exit_no_heap;
 		}
+
+		if (s_cols != NULL) {
+			UT_DELETE(s_cols);
+			mem_heap_free(s_heap);
+		}
 	}
 
 	if (!(ha_alter_info->handler_flags & INNOBASE_ALTER_DATA)
@@ -5989,7 +6304,7 @@ ha_innobase::prepare_inplace_alter_table(
 
 		}
 
-		/* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_VIRTUAL_COLUMNS
 		if ((ha_alter_info->handler_flags
 		     & Alter_inplace_info::DROP_VIRTUAL_COLUMN)
 		    && prepare_inplace_drop_virtual(
@@ -6003,7 +6318,7 @@ ha_innobase::prepare_inplace_alter_table(
 			    ha_alter_info, altered_table, table)) {
 			DBUG_RETURN(true);
 		}
-		*/
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 
 		DBUG_RETURN(false);
 	}
@@ -6020,8 +6335,6 @@ ha_innobase::prepare_inplace_alter_table(
 			    altered_table, &fts_doc_col_no, &num_v)) {
 
 			fts_doc_col_no = altered_table->s->stored_fields;
-
-			fts_doc_col_no = altered_table->s->fields - num_v;
 			add_fts_doc_id = true;
 			add_fts_doc_id_idx = true;
 
@@ -6061,21 +6374,24 @@ ha_innobase::prepare_inplace_alter_table(
 
 	/* See if an AUTO_INCREMENT column was added. */
 	uint i = 0, innodb_idx= 0;
+	ulint	num_v = 0;
 	List_iterator_fast<Create_field> cf_it(
 		ha_alter_info->alter_info->create_list);
 	while (const Create_field* new_field = cf_it++) {
 		const Field*	field;
-                if (!new_field->stored_in_db()) {
-                  i++;
-                  continue;
-                }
+		if (!new_field->stored_in_db()) {
+			i++;
+			continue;
+		}
 
 		DBUG_ASSERT(i < altered_table->s->fields);
 		DBUG_ASSERT(innodb_idx < altered_table->s->stored_fields);
 
 		for (uint old_i = 0; table->field[old_i]; old_i++) {
-                        if (!table->field[old_i]->stored_in_db())
-                          continue;
+			if (!table->field[old_i]->stored_in_db()) {
+				continue;
+			}
+
 			if (new_field->field == table->field[old_i]) {
 				goto found_col;
 			}
@@ -6108,8 +6424,12 @@ ha_innobase::prepare_inplace_alter_table(
 			autoinc_col_max_value = innobase_get_int_col_max_value(field);
 		}
 found_col:
+		if (innobase_is_v_fld(new_field)) {
+			++num_v;
+		}
+
 		i++;
-                innodb_idx++;
+		innodb_idx++;
 	}
 
 	DBUG_ASSERT(heap);
@@ -6135,6 +6455,72 @@ ha_innobase::prepare_inplace_alter_table(
 			    add_fts_doc_id_idx));
 }
 
+/** Check that the column is part of a virtual index(index contains
+virtual column) in the table
+ at param[in]	table		Table containing column
+ at param[in]	col		column to be checked
+ at return true if this column is indexed with other virtual columns */
+static
+bool
+dict_col_in_v_indexes(
+	dict_table_t*	table,
+	dict_col_t*	col)
+{
+	for (dict_index_t* index = dict_table_get_next_index(
+		dict_table_get_first_index(table)); index != NULL;
+		index = dict_table_get_next_index(index)) {
+		if (!dict_index_has_virtual(index)) {
+			continue;
+		}
+		for (ulint k = 0; k < index->n_fields; k++) {
+			dict_field_t*   field
+				= dict_index_get_nth_field(index, k);
+			if (field->col->ind == col->ind) {
+				return(true);
+			}
+		}
+	}
+
+	return(false);
+}
+
+/* Check whether a columnn length change alter operation requires
+to rebuild the template.
+ at param[in]	altered_table	TABLE object for new version of table.
+ at param[in]	ha_alter_info	Structure describing changes to be done
+				by ALTER TABLE and holding data used
+				during in-place alter.
+ at param[in]	table		table being altered
+ at return TRUE if needs rebuild. */
+static
+bool
+alter_templ_needs_rebuild(
+	TABLE*                  altered_table,
+	Alter_inplace_info*     ha_alter_info,
+	dict_table_t*		table)
+{
+        ulint	i = 0;
+        List_iterator_fast<Create_field>  cf_it(
+                ha_alter_info->alter_info->create_list);
+
+	for (Field** fp = altered_table->field; *fp; fp++, i++) {
+		cf_it.rewind();
+		while (const Create_field* cf = cf_it++) {
+			for (ulint j=0; j < table->n_cols; j++) {
+				dict_col_t* cols
+                                   = dict_table_get_nth_col(table, j);
+				if (cf->length > cols->len
+				    && dict_col_in_v_indexes(table, cols)) {
+					return(true);
+				}
+			}
+		}
+	}
+
+	return(false);
+}
+
+
 /** Alter the table structure in-place with operations
 specified using Alter_inplace_info.
 The level of concurrency allowed during this operation depends
@@ -6156,10 +6542,10 @@ ha_innobase::inplace_alter_table(
 {
 	dberr_t			error;
 	dict_add_v_col_t*	add_v = NULL;
-	innodb_col_templ_t*	s_templ = NULL;
-	innodb_col_templ_t*	old_templ = NULL;
-
-
+	dict_vcol_templ_t*	s_templ = NULL;
+	dict_vcol_templ_t*	old_templ = NULL;
+	struct TABLE*		eval_table = altered_table;
+	bool			rebuild_templ = false;
 	DBUG_ENTER("inplace_alter_table");
 	DBUG_ASSERT(!srv_read_only_mode);
 
@@ -6168,7 +6554,6 @@ ha_innobase::inplace_alter_table(
 
 	DEBUG_SYNC(m_user_thd, "innodb_inplace_alter_table_enter");
 
-
 	if (!(ha_alter_info->handler_flags & INNOBASE_ALTER_DATA)) {
 ok_exit:
 		DEBUG_SYNC(m_user_thd, "innodb_after_inplace_alter_table");
@@ -6208,10 +6593,24 @@ ha_innobase::inplace_alter_table(
 	that carries translation information between MySQL TABLE and InnoDB
 	table, which indicates the virtual columns and their base columns
 	info. This is used to do the computation callback, so that the
-	data in base columns can be extracted send to server */
-	if (ctx->need_rebuild() && ctx->new_table->n_v_cols) {
-		s_templ = static_cast<innodb_col_templ_t*>(
-			mem_heap_alloc(ctx->heap, sizeof *s_templ));
+	data in base columns can be extracted send to server.
+	If the Column length changes and it is a part of virtual
+	index then we need to rebuild the template. */
+	rebuild_templ
+	     = ctx->need_rebuild()
+	       || ((ha_alter_info->handler_flags
+		& Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH)
+		&& alter_templ_needs_rebuild(
+		   altered_table, ha_alter_info, ctx->new_table));
+
+#ifdef MYSQL_VIRTUAL_COLUMNS
+	if ((ctx->new_table->n_v_cols > 0) && rebuild_templ) {
+		/* Save the templ if isn't NULL so as to restore the
+		original state in case of alter operation failures. */
+		if (ctx->new_table->vc_templ != NULL && !ctx->need_rebuild()) {
+			old_templ = ctx->new_table->vc_templ;
+		}
+		s_templ = UT_NEW_NOKEY(dict_vcol_templ_t());
 		s_templ->vtempl = NULL;
 
 		innobase_build_v_templ(
@@ -6219,10 +6618,13 @@ ha_innobase::inplace_alter_table(
 			NULL, false, NULL);
 
 		ctx->new_table->vc_templ = s_templ;
-	} else if (ctx->num_to_add_vcol) {
-		ut_ad(!ctx->online);
-		s_templ = static_cast<innodb_col_templ_t*>(
-				mem_heap_alloc(ctx->heap, sizeof *s_templ));
+	} else if (ctx->num_to_add_vcol > 0 && ctx->num_to_drop_vcol == 0) {
+		/* if there is ongoing drop virtual column, then we disallow
+		inplace add index on newly added virtual column, so it does
+		not need to come in here to rebuild template with add_v.
+		Please also see the assertion in innodb_v_adjust_idx_col() */
+
+		s_templ = UT_NEW_NOKEY(dict_vcol_templ_t());
 
 		add_v = static_cast<dict_add_v_col_t*>(
 			mem_heap_alloc(ctx->heap, sizeof *add_v));
@@ -6239,6 +6641,14 @@ ha_innobase::inplace_alter_table(
 		ctx->new_table->vc_templ = s_templ;
 	}
 
+	/* Drop virtual column without rebuild will keep dict table
+	unchanged, we use old table to evaluate virtual column value
+	in innobase_get_computed_value(). */
+	if (!ctx->need_rebuild() && ctx->num_to_drop_vcol > 0) {
+		eval_table = table;
+	}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
 	/* Read the clustered index of the table and build
 	indexes based on this information using temporary
 	files and merge sort. */
@@ -6252,15 +6662,15 @@ ha_innobase::inplace_alter_table(
 		ctx->add_index, ctx->add_key_numbers, ctx->num_to_add_index,
 		altered_table, ctx->add_cols, ctx->col_map,
 		ctx->add_autoinc, ctx->sequence, ctx->skip_pk_sort,
-		ctx->m_stage, add_v);
+		ctx->m_stage, add_v, eval_table);
 
 	if (s_templ) {
-		ut_ad(ctx->need_rebuild() || ctx->num_to_add_vcol);
-		free_vc_templ(s_templ);
+		ut_ad(ctx->need_rebuild() || ctx->num_to_add_vcol > 0
+		      || rebuild_templ);
+		dict_free_vc_templ(s_templ);
+		UT_DELETE(s_templ);
 
-		if (old_templ) {
-			ctx->new_table->vc_templ = old_templ;
-		}
+		ctx->new_table->vc_templ = old_templ;
 	}
 
 #ifndef DBUG_OFF
@@ -6378,6 +6788,56 @@ innobase_online_rebuild_log_free(
 	rw_lock_x_unlock(&clust_index->lock);
 }
 
+/** For each user column, which is part of an index which is not going to be
+dropped, it checks if the column number of the column is same as col_no
+argument passed.
+ at param[in]	table	table object
+ at param[in]	col_no	column number of the column which is to be checked
+ at param[in]	is_v	if this is a virtual column
+ at retval true column exists
+ at retval false column does not exist, true if column is system column or
+it is in the index. */
+static
+bool
+check_col_exists_in_indexes(
+	const dict_table_t*	table,
+	ulint			col_no,
+	bool			is_v)
+{
+	/* This function does not check system columns */
+	if (!is_v && dict_table_get_nth_col(table, col_no)->mtype == DATA_SYS) {
+		return(true);
+	}
+
+	for (dict_index_t* index = dict_table_get_first_index(table); index;
+	     index = dict_table_get_next_index(index)) {
+
+		if (index->to_be_dropped) {
+			continue;
+		}
+
+		for (ulint i = 0; i < index->n_user_defined_cols; i++) {
+			const dict_col_t* idx_col
+				= dict_index_get_nth_col(index, i);
+
+			if (is_v && dict_col_is_virtual(idx_col)) {
+				const dict_v_col_t*   v_col = reinterpret_cast<
+					const dict_v_col_t*>(idx_col);
+				if (v_col->v_pos == col_no) {
+					return(true);
+				}
+			}
+
+			if (!is_v && !dict_col_is_virtual(idx_col)
+			    && dict_col_get_no(idx_col) == col_no) {
+				return(true);
+			}
+		}
+	}
+
+	return(false);
+}
+
 /** Rollback a secondary index creation, drop the indexes with
 temparary index prefix
 @param user_table InnoDB table
@@ -6527,6 +6987,21 @@ rollback_inplace_alter_table(
 		}
 	}
 
+	/* Reset dict_col_t::ord_part for those columns fail to be indexed,
+	we do this by checking every existing column, if any current
+	index would index them */
+	for (ulint i = 0; i < dict_table_get_n_cols(prebuilt->table); i++) {
+		if (!check_col_exists_in_indexes(prebuilt->table, i, false)) {
+			prebuilt->table->cols[i].ord_part = 0;
+		}
+	}
+
+	for (ulint i = 0; i < dict_table_get_n_v_cols(prebuilt->table); i++) {
+		if (!check_col_exists_in_indexes(prebuilt->table, i, true)) {
+			prebuilt->table->v_cols[i].m_col.ord_part = 0;
+		}
+	}
+
 	trx_commit_for_mysql(prebuilt->trx);
 	MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE);
 	DBUG_RETURN(fail);
@@ -6822,8 +7297,8 @@ innobase_rename_columns_try(
 
 	for (Field** fp = table->field; *fp; fp++, i++) {
 		bool	is_virtual = innobase_is_v_fld(*fp);
-		if (!((*fp)->flags & FIELD_IS_RENAMED) || !((*fp)->stored_in_db())) {
 
+		if (!((*fp)->flags & FIELD_IS_RENAMED)) {
 			goto processed_field;
 		}
 
@@ -6866,9 +7341,10 @@ innobase_rename_columns_try(
 @param table_name Table name in MySQL
 @param nth_col 0-based index of the column
 @param new_len new column length, in bytes
+ at param is_v if it's a virtual column
 @retval true Failure
 @retval false Success */
-static __attribute__((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((nonnull, warn_unused_result))
 bool
 innobase_enlarge_column_try(
 /*========================*/
@@ -6876,10 +7352,16 @@ innobase_enlarge_column_try(
 	trx_t*			trx,
 	const char*		table_name,
 	ulint			nth_col,
-	ulint			new_len)
+	ulint			new_len,
+	bool			is_v)
 {
 	pars_info_t*	info;
 	dberr_t		error;
+#ifdef UNIV_DEBUG
+	dict_col_t*	col;
+#endif /* UNIV_DEBUG */
+	dict_v_col_t*	v_col;
+	ulint		pos;
 
 	DBUG_ENTER("innobase_enlarge_column_try");
 
@@ -6887,9 +7369,23 @@ innobase_enlarge_column_try(
 	ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
 	ut_ad(mutex_own(&dict_sys->mutex));
 	ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
-	ut_ad(dict_table_get_nth_col(user_table, nth_col)->len < new_len);
+
+	if (is_v) {
+		v_col = dict_table_get_nth_v_col(user_table, nth_col);
+		pos = dict_create_v_col_pos(v_col->v_pos, v_col->m_col.ind);
+#ifdef UNIV_DEBUG
+		col = &v_col->m_col;
+#endif /* UNIV_DEBUG */
+	} else {
 #ifdef UNIV_DEBUG
-	switch (dict_table_get_nth_col(user_table, nth_col)->mtype) {
+		col = dict_table_get_nth_col(user_table, nth_col);
+#endif /* UNIV_DEBUG */
+		pos = nth_col;
+	}
+
+#ifdef UNIV_DEBUG
+	ut_ad(col->len < new_len);
+	switch (col->mtype) {
 	case DATA_MYSQL:
 		/* NOTE: we could allow this when !(prtype & DATA_BINARY_TYPE)
 		and ROW_FORMAT is not REDUNDANT and mbminlen<mbmaxlen.
@@ -6909,7 +7405,7 @@ innobase_enlarge_column_try(
 	info = pars_info_create();
 
 	pars_info_add_ull_literal(info, "tableid", user_table->id);
-	pars_info_add_int4_literal(info, "nth", nth_col);
+	pars_info_add_int4_literal(info, "nth", pos);
 	pars_info_add_int4_literal(info, "new", new_len);
 
 	trx->op_info = "resizing column in SYS_COLUMNS";
@@ -6945,7 +7441,7 @@ innobase_enlarge_column_try(
 @param table_name Table name in MySQL
 @retval true Failure
 @retval false Success */
-static __attribute__((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((nonnull, warn_unused_result))
 bool
 innobase_enlarge_columns_try(
 /*=========================*/
@@ -6957,9 +7453,27 @@ innobase_enlarge_columns_try(
 {
 	List_iterator_fast<Create_field> cf_it(
 		ha_alter_info->alter_info->create_list);
-	ulint i = 0;
+	ulint	i = 0;
+	bool	is_v=false;
 
 	for (Field** fp = table->field; *fp; fp++, i++) {
+		ulint	idx;
+
+#ifdef MYSQL_VIRTUAL_COLUMNS
+	ulint	num_v = 0;
+		if ((*fp)->is_virtual_gcol()) {
+			is_v = true;
+			idx = num_v;
+			num_v++;
+		} else {
+			idx = i - num_v;
+			is_v = false;
+		}
+#else
+		idx = i;
+		is_v = false;
+#endif
+
 		cf_it.rewind();
 		while (Create_field* cf = cf_it++) {
 			if (cf->field == *fp) {
@@ -6967,7 +7481,7 @@ innobase_enlarge_columns_try(
 				    == IS_EQUAL_PACK_LENGTH
 				    && innobase_enlarge_column_try(
 					    user_table, trx, table_name,
-					    i, cf->length)) {
+					    idx, cf->length, is_v)) {
 					return(true);
 				}
 
@@ -7468,8 +7982,8 @@ commit_try_rebuild(
 		/* Normally, n_ref_count must be 1, because purge
 		cannot be executing on this very table as we are
 		holding dict_operation_lock X-latch. */
-
-		error = DB_LOCK_WAIT_TIMEOUT;
+		my_error(ER_TABLE_REFERENCED,MYF(0));
+		DBUG_RETURN(true);
 	}
 
 	switch (error) {
@@ -7522,6 +8036,9 @@ commit_cache_rebuild(
 	DBUG_VOID_RETURN;
 }
 
+/** Set of column numbers */
+typedef std::set<ulint, std::less<ulint>, ut_allocator<ulint> >	col_set;
+
 /** Store the column number of the columns in a list belonging
 to indexes which are not being dropped.
 @param[in]	ctx		In-place ALTER TABLE context
@@ -7534,12 +8051,12 @@ static
 void
 get_col_list_to_be_dropped(
 	const ha_innobase_inplace_ctx*	ctx,
-	std::set<ulint>&		drop_col_list,
-	std::set<ulint>&		drop_v_col_list)
+	col_set&			drop_col_list,
+	col_set&			drop_v_col_list)
 {
 	for (ulint index_count = 0; index_count < ctx->num_to_drop_index;
 	     index_count++) {
-		const dict_index_t* index = ctx->drop_index[index_count];
+		const dict_index_t*	index = ctx->drop_index[index_count];
 
 		for (ulint col = 0; col < index->n_user_defined_cols; col++) {
 			const dict_col_t*	idx_col
@@ -7552,57 +8069,13 @@ get_col_list_to_be_dropped(
 				drop_v_col_list.insert(v_col->v_pos);
 
 			} else {
-				ulint col_no = dict_col_get_no(idx_col);
+				ulint	col_no = dict_col_get_no(idx_col);
 				drop_col_list.insert(col_no);
 			}
 		}
 	}
 }
 
-/** For each column, which is part of an index which is not going to be
-dropped, it checks if the column number of the column is same as col_no
-argument passed.
- at param[in]	table	table object
- at param[in]	col_no	column number of the column which is to be checked
- at param[in]	is_v	if this is a virtual column
- at retval true column exists
- at retval false column does not exist. */
-static
-bool
-check_col_exists_in_indexes(
-	const dict_table_t*	table,
-	ulint			col_no,
-	bool			is_v)
-{
-	for (dict_index_t* index = dict_table_get_first_index(table); index;
-	     index = dict_table_get_next_index(index)) {
-
-		if (index->to_be_dropped) {
-			continue;
-		}
-
-		for (ulint i = 0; i < index->n_user_defined_cols; i++) {
-			const dict_col_t* idx_col
-				= dict_index_get_nth_col(index, i);
-
-			if (is_v && dict_col_is_virtual(idx_col)) {
-				const dict_v_col_t*   v_col = reinterpret_cast<
-					const dict_v_col_t*>(idx_col);
-				if (v_col->v_pos == col_no) {
-					return(true);
-				}
-			}
-
-			if (!is_v && !dict_col_is_virtual(idx_col)
-			    && dict_col_get_no(idx_col) == col_no) {
-				return(true);
-			}
-		}
-	}
-
-	return(false);
-}
-
 /** Commit the changes made during prepare_inplace_alter_table()
 and inplace_alter_table() inside the data dictionary tables,
 when not rebuilding the table.
@@ -7636,31 +8109,6 @@ commit_try_norebuild(
 		    || ctx->num_to_drop_vcol
 		       == ha_alter_info->alter_info->drop_list.elements);
 
-
-	std::set<ulint> drop_list;
-	std::set<ulint> v_drop_list;
-	std::set<ulint>::iterator col_no;
-
-	/* Check if the column, part of an index to be dropped is part of any
-	other index which is not being dropped. If it so, then set the ord_part
-	of the column to 0. */
-        get_col_list_to_be_dropped(ctx, drop_list, v_drop_list);
-
-	for (col_no = drop_list.begin(); col_no != drop_list.end(); ++col_no) {
-		if (!check_col_exists_in_indexes(ctx->new_table,
-						 *col_no, false)) {
-			ctx->new_table->cols[*col_no].ord_part = 0;
-		}
-	}
-
-        for (col_no = v_drop_list.begin();
-	     col_no != v_drop_list.end(); ++col_no) {
-                if (!check_col_exists_in_indexes(ctx->new_table,
-						 *col_no, true)) {
-			ctx->new_table->v_cols[*col_no].m_col.ord_part = 0;
-                }
-	}
-
 	for (ulint i = 0; i < ctx->num_to_add_index; i++) {
 		dict_index_t*	index = ctx->add_index[i];
 		DBUG_ASSERT(dict_index_get_online_status(index)
@@ -7757,13 +8205,15 @@ commit_try_norebuild(
 		DBUG_RETURN(true);
 	}
 
-	/* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_RENAME_INDEX
 	if ((ha_alter_info->handler_flags
 	     & Alter_inplace_info::RENAME_INDEX)
 	    && rename_indexes_in_data_dictionary(ctx, ha_alter_info, trx)) {
 		DBUG_RETURN(true);
 	}
+#endif /* MYSQL_RENAME_INDEX */
 
+#ifdef MYSQL_VIRTUAL_COLUMNS
 	if ((ha_alter_info->handler_flags
 	     & Alter_inplace_info::DROP_VIRTUAL_COLUMN)
 	    && innobase_drop_virtual_try(
@@ -7779,7 +8229,7 @@ commit_try_norebuild(
 		    ctx->old_table, trx)) {
 		DBUG_RETURN(true);
 	}
-	*/
+#endif /* MYSQL_VIRTUAL_COLUMNS */
 
 	DBUG_RETURN(false);
 }
@@ -7805,6 +8255,30 @@ commit_cache_norebuild(
 
 	DBUG_ASSERT(!ctx->need_rebuild());
 
+	col_set			drop_list;
+	col_set			v_drop_list;
+	col_set::const_iterator col_it;
+
+	/* Check if the column, part of an index to be dropped is part of any
+	other index which is not being dropped. If it so, then set the ord_part
+	of the column to 0. */
+	get_col_list_to_be_dropped(ctx, drop_list, v_drop_list);
+
+	for (col_it = drop_list.begin(); col_it != drop_list.end(); ++col_it) {
+		if (!check_col_exists_in_indexes(ctx->new_table,
+						 *col_it, false)) {
+			ctx->new_table->cols[*col_it].ord_part = 0;
+		}
+	}
+
+	for (col_it = v_drop_list.begin();
+	     col_it != v_drop_list.end(); ++col_it) {
+		if (!check_col_exists_in_indexes(ctx->new_table,
+						 *col_it, true)) {
+			ctx->new_table->v_cols[*col_it].m_col.ord_part = 0;
+		}
+	}
+
 	for (ulint i = 0; i < ctx->num_to_add_index; i++) {
 		dict_index_t*	index = ctx->add_index[i];
 		DBUG_ASSERT(dict_index_get_online_status(index)
@@ -7940,7 +8414,7 @@ alter_stats_norebuild(
 		}
 	}
 
-	/* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_RENAME_INDEX
 	for (i = 0; i < ha_alter_info->index_rename_count; i++) {
 		KEY_PAIR*	pair = &ha_alter_info->index_rename_buffer[i];
 		dberr_t		err;
@@ -7963,7 +8437,7 @@ alter_stats_norebuild(
 				ut_strerr(err));
 		}
 	}
-	*/
+#endif /* MYSQL_RENAME_INDEX */
 
 	for (i = 0; i < ctx->num_to_add_index; i++) {
 		dict_index_t*	index = ctx->add_index[i];
@@ -8063,7 +8537,7 @@ ha_innobase::commit_inplace_alter_table(
 	Alter_inplace_info*	ha_alter_info,
 	bool			commit)
 {
-	dberr_t				error;
+	dberr_t	error;
 	ha_innobase_inplace_ctx*ctx0;
 	struct mtr_buf_copy_t	logs;
 
@@ -8153,7 +8627,7 @@ ha_innobase::commit_inplace_alter_table(
 		transactions collected during crash recovery could be
 		holding InnoDB locks only, not MySQL locks. */
 
-		dberr_t error = row_merge_lock_table(
+		error = row_merge_lock_table(
 			m_prebuilt->trx, ctx->old_table, LOCK_X);
 
 		if (error != DB_SUCCESS) {
@@ -8295,15 +8769,17 @@ ha_innobase::commit_inplace_alter_table(
 			DBUG_ASSERT(ctx->need_rebuild());
 			/* Check for any possible problems for any
 			file operations that will be performed in
-			commit_cache_rebuild(). */
-			if (!fil_mtr_rename_log(ctx->old_table,
-						ctx->new_table,
-						ctx->tmp_name, &mtr)) {
-				/* Out of memory. */
-				mtr.set_log_mode(MTR_LOG_NO_REDO);
-				mtr_commit(&mtr);
-				trx_rollback_for_mysql(trx);
+			commit_cache_rebuild(), and if none, generate
+			the redo log for these operations. */
+			error = fil_mtr_rename_log(ctx->old_table,
+						   ctx->new_table,
+						   ctx->tmp_name, &mtr);
+			if (error != DB_SUCCESS) {
+				/* Out of memory or a problem will occur
+				when renaming files. */
 				fail = true;
+				my_error_innodb(error, ctx->old_table->name.m_name,
+						ctx->old_table->flags);
 			}
 			DBUG_INJECT_CRASH("ib_commit_inplace_crash",
 					  crash_inject_count++);
@@ -8319,14 +8795,11 @@ ha_innobase::commit_inplace_alter_table(
 				DBUG_SUICIDE(););
 		ut_ad(!trx->fts_trx);
 
-		/* The following call commits the
-		mini-transaction, making the data dictionary
-		transaction committed at mtr.end_lsn. The
-		transaction becomes 'durable' by the time when
-		log_buffer_flush_to_disk() returns. In the
-		logical sense the commit in the file-based
-		data structures happens here. */
-		if (!fail) {
+		if (fail) {
+			mtr.set_log_mode(MTR_LOG_NO_REDO);
+			mtr_commit(&mtr);
+			trx_rollback_for_mysql(trx);
+		} else {
 			ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
 			ut_ad(trx_is_rseg_updated(trx));
 
@@ -8347,6 +8820,14 @@ ha_innobase::commit_inplace_alter_table(
 				log_append_on_checkpoint(&logs.m_buf);
 			}
 
+			/* The following call commits the
+			mini-transaction, making the data dictionary
+			transaction committed at mtr.end_lsn. The
+			transaction becomes 'durable' by the time when
+			log_buffer_flush_to_disk() returns. In the
+			logical sense the commit in the file-based
+			data structures happens here. */
+
 			trx_commit_low(trx, &mtr);
 		}
 
@@ -8371,7 +8852,6 @@ ha_innobase::commit_inplace_alter_table(
 	update the in-memory structures, close some handles, release
 	temporary files, and (unless we rolled back) update persistent
 	statistics. */
-
 	for (inplace_alter_handler_ctx** pctx = ctx_array;
 	     *pctx; pctx++) {
 		ha_innobase_inplace_ctx*	ctx
@@ -8459,10 +8939,16 @@ ha_innobase::commit_inplace_alter_table(
 				innobase_rename_or_enlarge_columns_cache(
 					ha_alter_info, table,
 					ctx->new_table);
-
+#ifdef MYSQL_RENAME_INDEX
 				rename_indexes_in_cache(ctx, ha_alter_info);
+#endif
 			}
+
 		}
+
+		dict_mem_table_free_foreign_vcol_set(ctx->new_table);
+		dict_mem_table_fill_foreign_vcol_set(ctx->new_table);
+
 		DBUG_INJECT_CRASH("ib_commit_inplace_crash",
 				  crash_inject_count++);
 	}
@@ -8507,6 +8993,14 @@ ha_innobase::commit_inplace_alter_table(
 
 	if (ctx0->num_to_drop_vcol || ctx0->num_to_add_vcol) {
 
+		if (ctx0->old_table->get_ref_count() > 1) {
+
+			row_mysql_unlock_data_dictionary(trx);
+			trx_free_for_mysql(trx);
+			my_error(ER_TABLE_REFERENCED,MYF(0));
+			DBUG_RETURN(true);
+		}
+
 		trx_commit_for_mysql(m_prebuilt->trx);
 
 		if (btr_search_enabled) {
@@ -8523,11 +9017,30 @@ ha_innobase::commit_inplace_alter_table(
 		dict_table_remove_from_cache(m_prebuilt->table);
 		m_prebuilt->table = dict_table_open_on_name(
 			tb_name, TRUE, TRUE, DICT_ERR_IGNORE_NONE);
+
+		/* Drop outdated table stats. */
+		char	errstr[1024];
+		if (dict_stats_drop_table(
+			    m_prebuilt->table->name.m_name,
+			    errstr, sizeof(errstr))
+		    != DB_SUCCESS) {
+			push_warning_printf(
+				m_user_thd,
+				Sql_condition::WARN_LEVEL_WARN,
+				ER_ALTER_INFO,
+				"Deleting persistent statistics"
+				" for table '%s' in"
+				" InnoDB failed: %s",
+				table->s->table_name.str,
+				errstr);
+		}
+
 		row_mysql_unlock_data_dictionary(trx);
 		trx_free_for_mysql(trx);
 		MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE);
 		DBUG_RETURN(false);
 	}
+
 	/* Release the table locks. */
 	trx_commit_for_mysql(m_prebuilt->trx);
 
@@ -8626,19 +9139,23 @@ ha_innobase::commit_inplace_alter_table(
 
 			row_prebuilt_free(ctx->prebuilt, TRUE);
 
-			if (ctx->new_table->n_v_cols
-			    && ctx->old_table->vc_templ) {
-				refresh_share_vtempl(
-					altered_table, ctx->new_table,
-					ctx->old_table->vc_templ->share_name);
-			}
 			/* Drop the copy of the old table, which was
 			renamed to ctx->tmp_name at the atomic DDL
 			transaction commit.  If the system crashes
 			before this is completed, some orphan tables
 			with ctx->tmp_name may be recovered. */
 			trx_start_for_ddl(trx, TRX_DICT_OP_TABLE);
-			row_merge_drop_table(trx, ctx->old_table);
+			error = row_merge_drop_table(trx, ctx->old_table);
+
+			if (error != DB_SUCCESS) {
+				ib::error() << "Inplace alter table " << ctx->old_table->name.m_name
+					    << " dropping copy of the old table failed error "
+					    << error
+					    << ". tmp_name " << (ctx->tmp_name ? ctx->tmp_name : "N/A")
+					    << " new_table " << (ctx->new_table ? ctx->new_table->name.m_name
+						    : "N/A");
+			}
+
 			trx_commit_for_mysql(trx);
 
 			/* Rebuild the prebuilt object. */
@@ -8760,6 +9277,332 @@ conveniance. */
 	}
 };
 
+#ifdef MYSQL_INNODB_PARTITIONING
+
+/** Check if supported inplace alter table.
+ at param[in]	altered_table	Altered MySQL table.
+ at param[in]	ha_alter_info	Information about inplace operations to do.
+ at return	Lock level, not supported or error */
+enum_alter_inplace_result
+ha_innopart::check_if_supported_inplace_alter(
+	TABLE*			altered_table,
+	Alter_inplace_info*	ha_alter_info)
+{
+	DBUG_ENTER("ha_innopart::check_if_supported_inplace_alter");
+	DBUG_ASSERT(ha_alter_info->handler_ctx == NULL);
+
+	/* Not supporting these for partitioned tables yet! */
+
+	/* FK not yet supported. */
+	if (ha_alter_info->handler_flags
+		& (Alter_inplace_info::ADD_FOREIGN_KEY
+			| Alter_inplace_info::DROP_FOREIGN_KEY)) {
+
+		ha_alter_info->unsupported_reason = innobase_get_err_msg(
+			ER_FOREIGN_KEY_ON_PARTITIONED);
+		DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+	}
+	/* FTS not yet supported either. */
+	if ((ha_alter_info->handler_flags
+		    & Alter_inplace_info::ADD_INDEX)) {
+
+		for (uint i = 0; i < ha_alter_info->index_add_count; i++) {
+			const KEY* key =
+				&ha_alter_info->key_info_buffer[
+					ha_alter_info->index_add_buffer[i]];
+			if (key->flags & HA_FULLTEXT) {
+				DBUG_ASSERT(!(key->flags & HA_KEYFLAG_MASK
+					      & ~(HA_FULLTEXT
+						  | HA_PACK_KEY
+						  | HA_GENERATED_KEY
+						  | HA_BINARY_PACK_KEY)));
+				ha_alter_info->unsupported_reason =
+					innobase_get_err_msg(
+					ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING);
+				DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+			}
+		}
+	}
+	/* We cannot allow INPLACE to change order of KEY partitioning fields! */
+	if ((ha_alter_info->handler_flags
+	     & Alter_inplace_info::ALTER_STORED_COLUMN_ORDER)
+	    && !m_part_info->same_key_column_order(
+				&ha_alter_info->alter_info->create_list)) {
+
+		DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+	}
+
+	/* Cannot allow INPLACE for drop and create PRIMARY KEY if partition is
+	on Primary Key - PARTITION BY KEY() */
+	if ((ha_alter_info->handler_flags
+	     & (Alter_inplace_info::ADD_PK_INDEX
+		| Alter_inplace_info::DROP_PK_INDEX))) {
+
+		/* Check partition by key(). */
+		if ((m_part_info->part_type == HASH_PARTITION)
+		    && m_part_info->list_of_part_fields
+		    && m_part_info->part_field_list.is_empty()) {
+
+			DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+		}
+
+		/* Check sub-partition by key(). */
+		if ((m_part_info->subpart_type == HASH_PARTITION)
+		    && m_part_info->list_of_subpart_fields
+		    && m_part_info->subpart_field_list.is_empty()) {
+
+			DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+		}
+	}
+
+	/* Check for PK and UNIQUE should already be done when creating the
+	new table metadata.
+	(fix_partition_info/check_primary_key+check_unique_key) */
+
+	set_partition(0);
+	DBUG_RETURN(ha_innobase::check_if_supported_inplace_alter(altered_table,
+							ha_alter_info));
+}
+
+/** Prepare inplace alter table.
+Allows InnoDB to update internal structures with concurrent
+writes blocked (provided that check_if_supported_inplace_alter()
+did not return HA_ALTER_INPLACE_NO_LOCK).
+This will be invoked before inplace_alter_table().
+ at param[in]	altered_table	TABLE object for new version of table.
+ at param[in]	ha_alter_info	Structure describing changes to be done
+by ALTER TABLE and holding data used during in-place alter.
+ at retval true Failure.
+ at retval false Success. */
+bool
+ha_innopart::prepare_inplace_alter_table(
+	TABLE*			altered_table,
+	Alter_inplace_info*	ha_alter_info)
+{
+	THD* thd;
+	ha_innopart_inplace_ctx* ctx_parts;
+	bool res = true;
+	DBUG_ENTER("ha_innopart::prepare_inplace_alter_table");
+	DBUG_ASSERT(ha_alter_info->handler_ctx == NULL);
+
+	thd = ha_thd();
+
+	/* Clean up all ins/upd nodes. */
+	clear_ins_upd_nodes();
+	/* Based on Sql_alloc class, return NULL for new on failure. */
+	ctx_parts = new ha_innopart_inplace_ctx(thd, m_tot_parts);
+	if (!ctx_parts) {
+		DBUG_RETURN(HA_ALTER_ERROR);
+	}
+
+	uint ctx_array_size = sizeof(inplace_alter_handler_ctx*)
+				* (m_tot_parts + 1);
+	ctx_parts->ctx_array =
+		static_cast<inplace_alter_handler_ctx**>(
+					ut_malloc(ctx_array_size,
+					mem_key_partitioning));
+	if (!ctx_parts->ctx_array) {
+		DBUG_RETURN(HA_ALTER_ERROR);
+	}
+
+	/* Set all to NULL, including the terminating one. */
+	memset(ctx_parts->ctx_array, 0, ctx_array_size);
+
+	ctx_parts->prebuilt_array = static_cast<row_prebuilt_t**>(
+					ut_malloc(sizeof(row_prebuilt_t*)
+							* m_tot_parts,
+					mem_key_partitioning));
+	if (!ctx_parts->prebuilt_array) {
+		DBUG_RETURN(HA_ALTER_ERROR);
+	}
+	/* For the first partition use the current prebuilt. */
+	ctx_parts->prebuilt_array[0] = m_prebuilt;
+	/* Create new prebuilt for the rest of the partitions.
+	It is needed for the current implementation of
+	ha_innobase::commit_inplace_alter_table(). */
+	for (uint i = 1; i < m_tot_parts; i++) {
+		row_prebuilt_t* tmp_prebuilt;
+		tmp_prebuilt = row_create_prebuilt(
+					m_part_share->get_table_part(i),
+					table_share->reclength);
+		/* Use same trx as original prebuilt. */
+		tmp_prebuilt->trx = m_prebuilt->trx;
+		ctx_parts->prebuilt_array[i] = tmp_prebuilt;
+	}
+
+	const char*	save_tablespace =
+		ha_alter_info->create_info->tablespace;
+
+	const char*	save_data_file_name =
+		ha_alter_info->create_info->data_file_name;
+
+	for (uint i = 0; i < m_tot_parts; i++) {
+		m_prebuilt = ctx_parts->prebuilt_array[i];
+		m_prebuilt_ptr = ctx_parts->prebuilt_array + i;
+		ha_alter_info->handler_ctx = ctx_parts->ctx_array[i];
+		set_partition(i);
+
+		/* Set the tablespace and data_file_name value of the
+		alter_info to the tablespace value and data_file_name
+		value that was existing for the partition originally,
+		so that for ALTER TABLE the tablespace clause in create
+		option is ignored for existing partitions, and later
+		set it back to its old value */
+
+		ha_alter_info->create_info->tablespace =
+			m_prebuilt->table->tablespace;
+		ha_alter_info->create_info->data_file_name =
+			m_prebuilt->table->data_dir_path;
+
+		res = ha_innobase::prepare_inplace_alter_table(altered_table,
+							ha_alter_info);
+		update_partition(i);
+		ctx_parts->ctx_array[i] = ha_alter_info->handler_ctx;
+		if (res) {
+			break;
+		}
+	}
+	m_prebuilt = ctx_parts->prebuilt_array[0];
+	m_prebuilt_ptr = &m_prebuilt;
+	ha_alter_info->handler_ctx = ctx_parts;
+	ha_alter_info->group_commit_ctx = ctx_parts->ctx_array;
+	ha_alter_info->create_info->tablespace = save_tablespace;
+	ha_alter_info->create_info->data_file_name = save_data_file_name;
+	DBUG_RETURN(res);
+}
+
+/** Inplace alter table.
+Alter the table structure in-place with operations
+specified using Alter_inplace_info.
+The level of concurrency allowed during this operation depends
+on the return value from check_if_supported_inplace_alter().
+ at param[in]	altered_table	TABLE object for new version of table.
+ at param[in]	ha_alter_info	Structure describing changes to be done
+by ALTER TABLE and holding data used during in-place alter.
+ at retval true Failure.
+ at retval false Success. */
+bool
+ha_innopart::inplace_alter_table(
+	TABLE*			altered_table,
+	Alter_inplace_info*	ha_alter_info)
+{
+	bool res = true;
+	ha_innopart_inplace_ctx* ctx_parts;
+
+	ctx_parts = static_cast<ha_innopart_inplace_ctx*>(
+					ha_alter_info->handler_ctx);
+	for (uint i = 0; i < m_tot_parts; i++) {
+		m_prebuilt = ctx_parts->prebuilt_array[i];
+		ha_alter_info->handler_ctx = ctx_parts->ctx_array[i];
+		set_partition(i);
+		res = ha_innobase::inplace_alter_table(altered_table,
+						ha_alter_info);
+		ut_ad(ctx_parts->ctx_array[i] == ha_alter_info->handler_ctx);
+		ctx_parts->ctx_array[i] = ha_alter_info->handler_ctx;
+		if (res) {
+			break;
+		}
+	}
+	m_prebuilt = ctx_parts->prebuilt_array[0];
+	ha_alter_info->handler_ctx = ctx_parts;
+	return(res);
+}
+
+/** Commit or rollback inplace alter table.
+Commit or rollback the changes made during
+prepare_inplace_alter_table() and inplace_alter_table() inside
+the storage engine. Note that the allowed level of concurrency
+during this operation will be the same as for
+inplace_alter_table() and thus might be higher than during
+prepare_inplace_alter_table(). (E.g concurrent writes were
+blocked during prepare, but might not be during commit).
+ at param[in]	altered_table	TABLE object for new version of table.
+ at param[in]	ha_alter_info	Structure describing changes to be done
+by ALTER TABLE and holding data used during in-place alter.
+ at param[in]	commit		true => Commit, false => Rollback.
+ at retval true Failure.
+ at retval false Success. */
+bool
+ha_innopart::commit_inplace_alter_table(
+	TABLE*			altered_table,
+	Alter_inplace_info*	ha_alter_info,
+	bool			commit)
+{
+	bool res = false;
+	ha_innopart_inplace_ctx* ctx_parts;
+
+	ctx_parts = static_cast<ha_innopart_inplace_ctx*>(
+					ha_alter_info->handler_ctx);
+	ut_ad(ctx_parts);
+	ut_ad(ctx_parts->prebuilt_array);
+	ut_ad(ctx_parts->prebuilt_array[0] == m_prebuilt);
+	if (commit) {
+		/* Commit is done through first partition (group commit). */
+		ut_ad(ha_alter_info->group_commit_ctx == ctx_parts->ctx_array);
+		ha_alter_info->handler_ctx = ctx_parts->ctx_array[0];
+		set_partition(0);
+		res = ha_innobase::commit_inplace_alter_table(altered_table,
+							ha_alter_info,
+							commit);
+		ut_ad(res || !ha_alter_info->group_commit_ctx);
+		goto end;
+	}
+	/* Rollback is done for each partition. */
+	for (uint i = 0; i < m_tot_parts; i++) {
+		m_prebuilt = ctx_parts->prebuilt_array[i];
+		ha_alter_info->handler_ctx = ctx_parts->ctx_array[i];
+		set_partition(i);
+		if (ha_innobase::commit_inplace_alter_table(altered_table,
+						ha_alter_info, commit)) {
+			res = true;
+		}
+		ut_ad(ctx_parts->ctx_array[i] == ha_alter_info->handler_ctx);
+		ctx_parts->ctx_array[i] = ha_alter_info->handler_ctx;
+	}
+end:
+	/* Move the ownership of the new tables back to
+	the m_part_share. */
+	ha_innobase_inplace_ctx*	ctx;
+	for (uint i = 0; i < m_tot_parts; i++) {
+		/* TODO: Fix to only use one prebuilt (i.e. make inplace
+		alter partition aware instead of using multiple prebuilt
+		copies... */
+		ctx = static_cast<ha_innobase_inplace_ctx*>(
+					ctx_parts->ctx_array[i]);
+		if (ctx) {
+			m_part_share->set_table_part(i, ctx->prebuilt->table);
+			ctx->prebuilt->table = NULL;
+			ctx_parts->prebuilt_array[i] = ctx->prebuilt;
+		}
+	}
+	/* The above juggling of prebuilt must be reset here. */
+	m_prebuilt = ctx_parts->prebuilt_array[0];
+	m_prebuilt->table = m_part_share->get_table_part(0);
+	ha_alter_info->handler_ctx = ctx_parts;
+	return(res);
+}
+
+/** Notify the storage engine that the table structure (.frm) has
+been updated.
+
+ha_partition allows inplace operations that also upgrades the engine
+if it supports partitioning natively. So if this is the case then
+we will remove the .par file since it is not used with ha_innopart
+(we use the internal data dictionary instead). */
+void
+ha_innopart::notify_table_changed()
+{
+	char	tmp_par_path[FN_REFLEN + 1];
+	strxnmov(tmp_par_path, FN_REFLEN, table->s->normalized_path.str,
+		".par", NullS);
+
+	if (my_access(tmp_par_path, W_OK) == 0)
+	{
+		my_delete(tmp_par_path, MYF(0));
+	}
+}
+#endif /* MYSQL_INNODB_PARTITIONING */
+
 /**
 @param thd the session
 @param start_value the lower bound
diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
index 3d7124c..524cbc8 100644
--- a/storage/innobase/handler/i_s.cc
+++ b/storage/innobase/handler/i_s.cc
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2007, 2015, Oracle and/or its affiliates.
+Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved.
 Copyrigth (c) 2014, 2016, MariaDB Corporation
 
 This program is free software; you can redistribute it and/or modify it under
@@ -111,6 +111,7 @@ static buf_page_desc_t	i_s_page_type[] = {
 	{"RTREE_INDEX", I_S_PAGE_TYPE_RTREE},
 	{"IBUF_INDEX", I_S_PAGE_TYPE_IBUF},
 	{"PAGE COMPRESSED", FIL_PAGE_PAGE_COMPRESSED},
+	{"PAGE COMPRESSED AND ENCRYPTED", FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED},
 };
 
 /** This structure defines information we will fetch from pages
@@ -315,7 +316,7 @@ field_store_index_name(
 
 /*******************************************************************//**
 Auxiliary function to store ulint value in MYSQL_TYPE_LONGLONG field.
-If the value is ULINT_UNDEFINED then the field it set to NULL.
+If the value is ULINT_UNDEFINED then the field is set to NULL.
 @return 0 on success */
 int
 field_store_ulint(
@@ -327,7 +328,7 @@ field_store_ulint(
 
 	if (n != ULINT_UNDEFINED) {
 
-		ret = field->store(static_cast<double>(n));
+		ret = field->store(n, true);
 		field->set_notnull();
 	} else {
 
@@ -628,12 +629,11 @@ fill_innodb_trx_from_cache(
 		}
 
 		/* trx_weight */
-		OK(fields[IDX_TRX_WEIGHT]->store((longlong) row->trx_weight,
-						 true));
+		OK(fields[IDX_TRX_WEIGHT]->store(row->trx_weight, true));
 
 		/* trx_mysql_thread_id */
 		OK(fields[IDX_TRX_MYSQL_THREAD_ID]->store(
-			   static_cast<double>(row->trx_mysql_thread_id)));
+			   row->trx_mysql_thread_id, true));
 
 		/* trx_query */
 		if (row->trx_query) {
@@ -654,31 +654,31 @@ fill_innodb_trx_from_cache(
 
 		/* trx_tables_in_use */
 		OK(fields[IDX_TRX_TABLES_IN_USE]->store(
-			   (longlong) row->trx_tables_in_use, true));
+			   row->trx_tables_in_use, true));
 
 		/* trx_tables_locked */
 		OK(fields[IDX_TRX_TABLES_LOCKED]->store(
-			   (longlong) row->trx_tables_locked, true));
+			   row->trx_tables_locked, true));
 
 		/* trx_lock_structs */
 		OK(fields[IDX_TRX_LOCK_STRUCTS]->store(
-			   (longlong) row->trx_lock_structs, true));
+			   row->trx_lock_structs, true));
 
 		/* trx_lock_memory_bytes */
 		OK(fields[IDX_TRX_LOCK_MEMORY_BYTES]->store(
-			   (longlong) row->trx_lock_memory_bytes, true));
+			   row->trx_lock_memory_bytes, true));
 
 		/* trx_rows_locked */
 		OK(fields[IDX_TRX_ROWS_LOCKED]->store(
-			   (longlong) row->trx_rows_locked, true));
+			   row->trx_rows_locked, true));
 
 		/* trx_rows_modified */
 		OK(fields[IDX_TRX_ROWS_MODIFIED]->store(
-			   (longlong) row->trx_rows_modified, true));
+			   row->trx_rows_modified, true));
 
 		/* trx_concurrency_tickets */
 		OK(fields[IDX_TRX_CONNCURRENCY_TICKETS]->store(
-			   (longlong) row->trx_concurrency_tickets, true));
+			   row->trx_concurrency_tickets, true));
 
 		/* trx_isolation_level */
 		OK(field_store_string(fields[IDX_TRX_ISOLATION_LEVEL],
@@ -686,11 +686,11 @@ fill_innodb_trx_from_cache(
 
 		/* trx_unique_checks */
 		OK(fields[IDX_TRX_UNIQUE_CHECKS]->store(
-			   static_cast<double>(row->trx_unique_checks)));
+			   row->trx_unique_checks, true));
 
 		/* trx_foreign_key_checks */
 		OK(fields[IDX_TRX_FOREIGN_KEY_CHECKS]->store(
-			   static_cast<double>(row->trx_foreign_key_checks)));
+			   row->trx_foreign_key_checks, true));
 
 		/* trx_last_foreign_key_error */
 		OK(field_store_string(fields[IDX_TRX_LAST_FOREIGN_KEY_ERROR],
@@ -698,16 +698,16 @@ fill_innodb_trx_from_cache(
 
 		/* trx_adaptive_hash_latched */
 		OK(fields[IDX_TRX_ADAPTIVE_HASH_LATCHED]->store(
-			   static_cast<double>(row->trx_has_search_latch)));
+			   row->trx_has_search_latch, true));
 
 		/* trx_is_read_only*/
 		OK(fields[IDX_TRX_READ_ONLY]->store(
-				(longlong) row->trx_is_read_only, true));
+			   row->trx_is_read_only, true));
 
 		/* trx_is_autocommit_non_locking */
 		OK(fields[IDX_TRX_AUTOCOMMIT_NON_LOCKING]->store(
-				(longlong) row->trx_is_autocommit_non_locking,
-				true));
+			   (longlong) row->trx_is_autocommit_non_locking,
+			   true));
 
 		OK(schema_table_store_record(thd, table));
 	}
@@ -947,7 +947,7 @@ fill_innodb_locks_from_cache(
 					       strlen(row->lock_table),
 					       thd);
 		OK(fields[IDX_LOCK_TABLE]->store(
-			buf, static_cast<uint>(bufend - buf),
+			buf, static_cast<size_t>(bufend - buf),
 			system_charset_info));
 
 		/* lock_index */
@@ -1427,16 +1427,11 @@ i_s_cmp_fill_low(
 		clear it.  We could introduce mutex protection, but it
 		could cause a measureable performance hit in
 		page0zip.cc. */
-		table->field[1]->store(
-			static_cast<double>(zip_stat->compressed));
-		table->field[2]->store(
-			static_cast<double>(zip_stat->compressed_ok));
-		table->field[3]->store(
-			static_cast<double>(zip_stat->compressed_usec / 1000000));
-		table->field[4]->store(
-			static_cast<double>(zip_stat->decompressed));
-		table->field[5]->store(
-			static_cast<double>(zip_stat->decompressed_usec / 1000000));
+		table->field[1]->store(zip_stat->compressed, true);
+		table->field[2]->store(zip_stat->compressed_ok, true);
+		table->field[3]->store(zip_stat->compressed_usec / 1000000, true);
+		table->field[4]->store(zip_stat->decompressed, true);
+		table->field[5]->store(zip_stat->decompressed_usec / 1000000, true);
 
 		if (reset) {
 			memset(zip_stat, 0, sizeof *zip_stat);
@@ -1763,25 +1758,36 @@ i_s_cmp_per_index_fill_low(
 		}
 
 		fields[IDX_COMPRESS_OPS]->store(
-			static_cast<double>(iter->second.compressed));
+			   iter->second.compressed, true);
 
 		fields[IDX_COMPRESS_OPS_OK]->store(
-			static_cast<double>(iter->second.compressed_ok));
+			   iter->second.compressed_ok, true);
 
 		fields[IDX_COMPRESS_TIME]->store(
-			static_cast<double>(iter->second.compressed_usec / 1000000));
+			   iter->second.compressed_usec / 1000000, true);
 
 		fields[IDX_UNCOMPRESS_OPS]->store(
-			static_cast<double>(iter->second.decompressed));
+			   iter->second.decompressed, true);
 
 		fields[IDX_UNCOMPRESS_TIME]->store(
-			static_cast<double>(iter->second.decompressed_usec / 1000000));
+			   iter->second.decompressed_usec / 1000000, true);
 
+#ifdef MYSQL_SCHEMA_TABLE_STORE_RECORD2
+		int	error;
+		if ((error = schema_table_store_record2(thd, table, false))) {
+			mutex_exit(&dict_sys->mutex);
+			if (convert_heap_table_to_ondisk(thd, table, error) != 0) {
+				status = 1;
+				goto err;
+			}
+			mutex_enter(&dict_sys->mutex);
+		}
+#else
 		if (schema_table_store_record(thd, table)) {
 			status = 1;
 			break;
 		}
-
+#endif
 		/* Release and reacquire the dict mutex to allow other
 		threads to proceed. This could eventually result in the
 		contents of INFORMATION_SCHEMA.innodb_cmp_per_index being
@@ -1793,6 +1799,7 @@ i_s_cmp_per_index_fill_low(
 	}
 
 	mutex_exit(&dict_sys->mutex);
+err:
 
 	if (reset) {
 		page_zip_reset_stat_per_index();
@@ -2046,37 +2053,43 @@ i_s_cmpmem_fill_low(
 	RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
 
 	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
-		buf_pool_t*	buf_pool;
+		buf_pool_t*		buf_pool;
+		ulint			zip_free_len_local[BUF_BUDDY_SIZES_MAX + 1];
+		buf_buddy_stat_t	buddy_stat_local[BUF_BUDDY_SIZES_MAX + 1];
 
 		status	= 0;
 
 		buf_pool = buf_pool_from_array(i);
 
+		/* Save buddy stats for buffer pool in local variables. */
 		buf_pool_mutex_enter(buf_pool);
-
 		for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
-			buf_buddy_stat_t*	buddy_stat;
 
-			buddy_stat = &buf_pool->buddy_stat[x];
+			zip_free_len_local[x] = (x < BUF_BUDDY_SIZES) ?
+				UT_LIST_GET_LEN(buf_pool->zip_free[x]) : 0;
 
-			table->field[0]->store(BUF_BUDDY_LOW << x);
-			table->field[1]->store(static_cast<double>(i));
-			table->field[2]->store(static_cast<double>(
-				buddy_stat->used));
-			table->field[3]->store(static_cast<double>(
-				(x < BUF_BUDDY_SIZES)
-				? UT_LIST_GET_LEN(buf_pool->zip_free[x])
-				: 0));
-			table->field[4]->store(
-				(longlong) buddy_stat->relocated, true);
-			table->field[5]->store(
-				static_cast<double>(buddy_stat->relocated_usec / 1000000));
+			buddy_stat_local[x] = buf_pool->buddy_stat[x];
 
 			if (reset) {
 				/* This is protected by buf_pool->mutex. */
-				buddy_stat->relocated = 0;
-				buddy_stat->relocated_usec = 0;
+				buf_pool->buddy_stat[x].relocated = 0;
+				buf_pool->buddy_stat[x].relocated_usec = 0;
 			}
+		}
+		buf_pool_mutex_exit(buf_pool);
+
+		for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
+			buf_buddy_stat_t*	buddy_stat;
+
+			buddy_stat = &buddy_stat_local[x];
+
+			table->field[0]->store(BUF_BUDDY_LOW << x);
+			table->field[1]->store(i, true);
+			table->field[2]->store(buddy_stat->used, true);
+			table->field[3]->store(zip_free_len_local[x], true);
+			table->field[4]->store(buddy_stat->relocated, true);
+			table->field[5]->store(
+				buddy_stat->relocated_usec / 1000000, true);
 
 			if (schema_table_store_record(thd, table)) {
 				status = 1;
@@ -2084,8 +2097,6 @@ i_s_cmpmem_fill_low(
 			}
 		}
 
-		buf_pool_mutex_exit(buf_pool);
-
 		if (status) {
 			break;
 		}
@@ -2940,15 +2951,26 @@ i_s_fts_deleted_generic_fill(
 		DBUG_RETURN(0);
 	}
 
-	deleted = fts_doc_ids_create();
+	/* Prevent DDL to drop fts aux tables. */
+	rw_lock_s_lock(dict_operation_lock);
 
 	user_table = dict_table_open_on_name(
 		fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
 
 	if (!user_table) {
+		rw_lock_s_unlock(dict_operation_lock);
+
+		DBUG_RETURN(0);
+	} else if (!dict_table_has_fts_index(user_table)) {
+		dict_table_close(user_table, FALSE, FALSE);
+
+		rw_lock_s_unlock(dict_operation_lock);
+
 		DBUG_RETURN(0);
 	}
 
+	deleted = fts_doc_ids_create();
+
 	trx = trx_allocate_for_background();
 	trx->op_info = "Select for FTS DELETE TABLE";
 
@@ -2965,7 +2987,7 @@ i_s_fts_deleted_generic_fill(
 
 		doc_id = *(doc_id_t*) ib_vector_get_const(deleted->doc_ids, j);
 
-		OK(fields[I_S_FTS_DOC_ID]->store((longlong) doc_id, true));
+		OK(fields[I_S_FTS_DOC_ID]->store(doc_id, true));
 
 		OK(schema_table_store_record(thd, table));
 	}
@@ -2976,6 +2998,8 @@ i_s_fts_deleted_generic_fill(
 
 	dict_table_close(user_table, FALSE, FALSE);
 
+	rw_lock_s_unlock(dict_operation_lock);
+
 	DBUG_RETURN(0);
 }
 
@@ -3282,28 +3306,28 @@ i_s_fts_index_cache_fill_one_index(
 					pos = fts_decode_vlc(&ptr);
 
 					OK(field_store_string(
-						fields[I_S_FTS_WORD],
-						word_str));
+						   fields[I_S_FTS_WORD],
+						   word_str));
 
 					OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
-						(longlong) node->first_doc_id,
-						true));
+						   node->first_doc_id,
+						   true));
 
 					OK(fields[I_S_FTS_LAST_DOC_ID]->store(
-						(longlong) node->last_doc_id,
-						true));
+						   node->last_doc_id,
+						   true));
 
 					OK(fields[I_S_FTS_DOC_COUNT]->store(
-						static_cast<double>(node->doc_count)));
+						   node->doc_count, true));
 
 					OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
-						(longlong) doc_id, true));
+						   doc_id, true));
 
 					OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
-						static_cast<double>(pos)));
+						   pos, true));
 
 					OK(schema_table_store_record(
-						thd, table));
+						   thd, table));
 				}
 
 				++ptr;
@@ -3349,6 +3373,12 @@ i_s_fts_index_cache_fill(
 		DBUG_RETURN(0);
 	}
 
+	if (user_table->fts == NULL || user_table->fts->cache == NULL) {
+		dict_table_close(user_table, FALSE, FALSE);
+
+		DBUG_RETURN(0);
+	}
+
 	cache = user_table->fts->cache;
 
 	ut_a(cache);
@@ -3637,8 +3667,8 @@ i_s_fts_index_table_fill_one_fetch(
 					pos = fts_decode_vlc(&ptr);
 
 					OK(field_store_string(
-						fields[I_S_FTS_WORD],
-						word_str));
+						   fields[I_S_FTS_WORD],
+						   word_str));
 
 					OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
 						longlong(node->first_doc_id), true));
@@ -3647,16 +3677,16 @@ i_s_fts_index_table_fill_one_fetch(
 						longlong(node->last_doc_id), true));
 
 					OK(fields[I_S_FTS_DOC_COUNT]->store(
-						static_cast<double>(node->doc_count)));
+						   node->doc_count, true));
 
 					OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
 						longlong(doc_id), true));
 
 					OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
-						static_cast<double>(pos)));
+						   pos, true));
 
 					OK(schema_table_store_record(
-						thd, table));
+						   thd, table));
 				}
 
 				++ptr;
@@ -3780,10 +3810,15 @@ i_s_fts_index_table_fill(
 		DBUG_RETURN(0);
 	}
 
+	/* Prevent DDL to drop fts aux tables. */
+	rw_lock_s_lock(dict_operation_lock);
+
 	user_table = dict_table_open_on_name(
 		fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
 
 	if (!user_table) {
+		rw_lock_s_unlock(dict_operation_lock);
+
 		DBUG_RETURN(0);
 	}
 
@@ -3796,6 +3831,8 @@ i_s_fts_index_table_fill(
 
 	dict_table_close(user_table, FALSE, FALSE);
 
+	rw_lock_s_unlock(dict_operation_lock);
+
 	DBUG_RETURN(0);
 }
 
@@ -3931,14 +3968,21 @@ i_s_fts_config_fill(
 
 	fields = table->field;
 
+	/* Prevent DDL to drop fts aux tables. */
+	rw_lock_s_lock(dict_operation_lock);
+
 	user_table = dict_table_open_on_name(
 		fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
 
 	if (!user_table) {
+		rw_lock_s_unlock(dict_operation_lock);
+
 		DBUG_RETURN(0);
 	} else if (!dict_table_has_fts_index(user_table)) {
 		dict_table_close(user_table, FALSE, FALSE);
 
+		rw_lock_s_unlock(dict_operation_lock);
+
 		DBUG_RETURN(0);
 	}
 
@@ -3994,6 +4038,8 @@ i_s_fts_config_fill(
 
 	dict_table_close(user_table, FALSE, FALSE);
 
+	rw_lock_s_unlock(dict_operation_lock);
+
 	DBUG_RETURN(0);
 }
 
@@ -4158,9 +4204,10 @@ i_s_innodb_temp_table_info_fill(
 
 	fields = table->field;
 
-	OK(fields[IDX_TEMP_TABLE_ID]->store((double) info->m_table_id));
+	OK(fields[IDX_TEMP_TABLE_ID]->store(info->m_table_id, true));
 
-	OK(field_store_string(fields[IDX_TEMP_TABLE_NAME], info->m_table_name));
+	OK(field_store_string(
+		   fields[IDX_TEMP_TABLE_NAME], info->m_table_name));
 
 	OK(fields[IDX_TEMP_TABLE_N_COLS]->store(info->m_n_cols));
 
@@ -4340,9 +4387,8 @@ struct st_maria_plugin	i_s_innodb_temp_table_info =
 	/* struct st_mysql_sys_var** */
 	STRUCT_FLD(system_vars, NULL),
 
-        /* Maria extension */
 	STRUCT_FLD(version_info, INNODB_VERSION_STR),
-        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_BETA),
+	STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_GAMMA)
 };
 
 /* Fields of the dynamic table INNODB_BUFFER_POOL_STATS. */
@@ -4662,67 +4708,67 @@ i_s_innodb_stats_fill(
 	fields = table->field;
 
 	OK(fields[IDX_BUF_STATS_POOL_ID]->store(
-		static_cast<double>(info->pool_unique_id)));
+		   info->pool_unique_id, true));
 
 	OK(fields[IDX_BUF_STATS_POOL_SIZE]->store(
-		static_cast<double>(info->pool_size)));
+		   info->pool_size, true));
 
 	OK(fields[IDX_BUF_STATS_LRU_LEN]->store(
-		static_cast<double>(info->lru_len)));
+		   info->lru_len, true));
 
 	OK(fields[IDX_BUF_STATS_OLD_LRU_LEN]->store(
-		static_cast<double>(info->old_lru_len)));
+		   info->old_lru_len, true));
 
 	OK(fields[IDX_BUF_STATS_FREE_BUFFERS]->store(
-		static_cast<double>(info->free_list_len)));
+		   info->free_list_len, true));
 
 	OK(fields[IDX_BUF_STATS_FLUSH_LIST_LEN]->store(
-		static_cast<double>(info->flush_list_len)));
+		   info->flush_list_len, true));
 
 	OK(fields[IDX_BUF_STATS_PENDING_ZIP]->store(
-		static_cast<double>(info->n_pend_unzip)));
+		   info->n_pend_unzip, true));
 
 	OK(fields[IDX_BUF_STATS_PENDING_READ]->store(
-		static_cast<double>(info->n_pend_reads)));
+		   info->n_pend_reads, true));
 
 	OK(fields[IDX_BUF_STATS_FLUSH_LRU]->store(
-		static_cast<double>(info->n_pending_flush_lru)));
+		   info->n_pending_flush_lru, true));
 
 	OK(fields[IDX_BUF_STATS_FLUSH_LIST]->store(
-		static_cast<double>(info->n_pending_flush_list)));
+		   info->n_pending_flush_list, true));
 
 	OK(fields[IDX_BUF_STATS_PAGE_YOUNG]->store(
-		static_cast<double>(info->n_pages_made_young)));
+		   info->n_pages_made_young, true));
 
 	OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG]->store(
-		static_cast<double>(info->n_pages_not_made_young)));
+		   info->n_pages_not_made_young, true));
 
 	OK(fields[IDX_BUF_STATS_PAGE_YOUNG_RATE]->store(
-		info->page_made_young_rate));
+		   info->page_made_young_rate));
 
 	OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE]->store(
-		info->page_not_made_young_rate));
+		   info->page_not_made_young_rate));
 
 	OK(fields[IDX_BUF_STATS_PAGE_READ]->store(
-		static_cast<double>(info->n_pages_read)));
+		   info->n_pages_read, true));
 
 	OK(fields[IDX_BUF_STATS_PAGE_CREATED]->store(
-		static_cast<double>(info->n_pages_created)));
+		   info->n_pages_created, true));
 
 	OK(fields[IDX_BUF_STATS_PAGE_WRITTEN]->store(
-		static_cast<double>(info->n_pages_written)));
+		   info->n_pages_written, true));
 
 	OK(fields[IDX_BUF_STATS_GET]->store(
-		static_cast<double>(info->n_page_gets)));
+		   info->n_page_gets, true));
 
 	OK(fields[IDX_BUF_STATS_PAGE_READ_RATE]->store(
-		info->pages_read_rate));
+		   info->pages_read_rate));
 
 	OK(fields[IDX_BUF_STATS_PAGE_CREATE_RATE]->store(
-		info->pages_created_rate));
+		   info->pages_created_rate));
 
 	OK(fields[IDX_BUF_STATS_PAGE_WRITTEN_RATE]->store(
-		info->pages_written_rate));
+		   info->pages_written_rate));
 
 	if (info->n_page_get_delta) {
 		if (info->page_read_delta <= info->n_page_get_delta) {
@@ -4735,43 +4781,41 @@ i_s_innodb_stats_fill(
 		}
 
 		OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(
-			static_cast<double>(
-				1000 * info->young_making_delta
-				/ info->n_page_get_delta)));
+			   1000 * info->young_making_delta
+			   / info->n_page_get_delta, true));
 
 		OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(
-			static_cast<double>(
-				1000 * info->not_young_making_delta
-				/ info->n_page_get_delta)));
+			   1000 * info->not_young_making_delta
+			   / info->n_page_get_delta, true));
 	} else {
-		OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0));
-		OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(0));
-		OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(0));
+		OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0, true));
+		OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(0, true));
+		OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(0, true));
 	}
 
 	OK(fields[IDX_BUF_STATS_READ_AHREAD]->store(
-		static_cast<double>(info->n_ra_pages_read)));
+		   info->n_ra_pages_read, true));
 
 	OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICTED]->store(
-		static_cast<double>(info->n_ra_pages_evicted)));
+		   info->n_ra_pages_evicted, true));
 
 	OK(fields[IDX_BUF_STATS_READ_AHEAD_RATE]->store(
-		info->pages_readahead_rate));
+		   info->pages_readahead_rate));
 
 	OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICT_RATE]->store(
-		info->pages_evicted_rate));
+		   info->pages_evicted_rate));
 
 	OK(fields[IDX_BUF_STATS_LRU_IO_SUM]->store(
-		static_cast<double>(info->io_sum)));
+		   info->io_sum, true));
 
 	OK(fields[IDX_BUF_STATS_LRU_IO_CUR]->store(
-		static_cast<double>(info->io_cur)));
+		   info->io_cur, true));
 
 	OK(fields[IDX_BUF_STATS_UNZIP_SUM]->store(
-		static_cast<double>(info->unzip_sum)));
+		   info->unzip_sum, true));
 
 	OK(fields[IDX_BUF_STATS_UNZIP_CUR]->store(
-		static_cast<double>(info->unzip_cur)));
+		   info->unzip_cur, true));
 
 	DBUG_RETURN(schema_table_store_record(thd, table));
 }
@@ -5117,43 +5161,43 @@ i_s_innodb_buffer_page_fill(
 		state_str = NULL;
 
 		OK(fields[IDX_BUFFER_POOL_ID]->store(
-			static_cast<double>(page_info->pool_id)));
+			   page_info->pool_id, true));
 
 		OK(fields[IDX_BUFFER_BLOCK_ID]->store(
-			static_cast<double>(page_info->block_id)));
+			   page_info->block_id, true));
 
 		OK(fields[IDX_BUFFER_PAGE_SPACE]->store(
-			static_cast<double>(page_info->space_id)));
+			   page_info->space_id, true));
 
 		OK(fields[IDX_BUFFER_PAGE_NUM]->store(
-			static_cast<double>(page_info->page_num)));
+			   page_info->page_num, true));
 
 		OK(field_store_string(
-			fields[IDX_BUFFER_PAGE_TYPE],
-			i_s_page_type[page_info->page_type].type_str));
+			   fields[IDX_BUFFER_PAGE_TYPE],
+			   i_s_page_type[page_info->page_type].type_str));
 
 		OK(fields[IDX_BUFFER_PAGE_FLUSH_TYPE]->store(
-			page_info->flush_type));
+			   page_info->flush_type));
 
 		OK(fields[IDX_BUFFER_PAGE_FIX_COUNT]->store(
-			page_info->fix_count));
+			   page_info->fix_count));
 
 		if (page_info->hashed) {
 			OK(field_store_string(
-				fields[IDX_BUFFER_PAGE_HASHED], "YES"));
+				   fields[IDX_BUFFER_PAGE_HASHED], "YES"));
 		} else {
 			OK(field_store_string(
-				fields[IDX_BUFFER_PAGE_HASHED], "NO"));
+				   fields[IDX_BUFFER_PAGE_HASHED], "NO"));
 		}
 
 		OK(fields[IDX_BUFFER_PAGE_NEWEST_MOD]->store(
-			(longlong) page_info->newest_mod, true));
+			   page_info->newest_mod, true));
 
 		OK(fields[IDX_BUFFER_PAGE_OLDEST_MOD]->store(
-			(longlong) page_info->oldest_mod, true));
+			   page_info->oldest_mod, true));
 
 		OK(fields[IDX_BUFFER_PAGE_ACCESS_TIME]->store(
-			page_info->access_time));
+			   page_info->access_time));
 
 		fields[IDX_BUFFER_PAGE_TABLE_NAME]->set_null();
 
@@ -5178,7 +5222,7 @@ i_s_innodb_buffer_page_fill(
 
 				OK(fields[IDX_BUFFER_PAGE_TABLE_NAME]->store(
 					table_name,
-					static_cast<uint>(table_name_end - table_name),
+					static_cast<size_t>(table_name_end - table_name),
 					system_charset_info));
 				fields[IDX_BUFFER_PAGE_TABLE_NAME]->set_notnull();
 
@@ -5191,15 +5235,15 @@ i_s_innodb_buffer_page_fill(
 		}
 
 		OK(fields[IDX_BUFFER_PAGE_NUM_RECS]->store(
-			page_info->num_recs));
+			   page_info->num_recs, true));
 
 		OK(fields[IDX_BUFFER_PAGE_DATA_SIZE]->store(
-			page_info->data_size));
+			   page_info->data_size, true));
 
 		OK(fields[IDX_BUFFER_PAGE_ZIP_SIZE]->store(
-			page_info->zip_ssize
-			? (UNIV_ZIP_SIZE_MIN >> 1) << page_info->zip_ssize
-			: 0));
+			   page_info->zip_ssize
+			   ? (UNIV_ZIP_SIZE_MIN >> 1) << page_info->zip_ssize
+			   : 0, true));
 
 #if BUF_PAGE_STATE_BITS > 3
 # error "BUF_PAGE_STATE_BITS > 3, please ensure that all 1<<BUF_PAGE_STATE_BITS values are checked for"
@@ -5258,7 +5302,7 @@ i_s_innodb_buffer_page_fill(
 				      (page_info->is_old) ? "YES" : "NO"));
 
 		OK(fields[IDX_BUFFER_PAGE_FREE_CLOCK]->store(
-			page_info->freed_page_clock));
+			   page_info->freed_page_clock, true));
 
 		if (schema_table_store_record(thd, table)) {
 			DBUG_RETURN(1);
@@ -5835,43 +5879,43 @@ i_s_innodb_buf_page_lru_fill(
 		page_info = info_array + i;
 
 		OK(fields[IDX_BUF_LRU_POOL_ID]->store(
-			static_cast<double>(page_info->pool_id)));
+			   page_info->pool_id, true));
 
 		OK(fields[IDX_BUF_LRU_POS]->store(
-			static_cast<double>(page_info->block_id)));
+			   page_info->block_id, true));
 
 		OK(fields[IDX_BUF_LRU_PAGE_SPACE]->store(
-			static_cast<double>(page_info->space_id)));
+			   page_info->space_id, true));
 
 		OK(fields[IDX_BUF_LRU_PAGE_NUM]->store(
-			static_cast<double>(page_info->page_num)));
+			   page_info->page_num, true));
 
 		OK(field_store_string(
-			fields[IDX_BUF_LRU_PAGE_TYPE],
-			i_s_page_type[page_info->page_type].type_str));
+			   fields[IDX_BUF_LRU_PAGE_TYPE],
+			   i_s_page_type[page_info->page_type].type_str));
 
 		OK(fields[IDX_BUF_LRU_PAGE_FLUSH_TYPE]->store(
-			static_cast<double>(page_info->flush_type)));
+			   page_info->flush_type, true));
 
 		OK(fields[IDX_BUF_LRU_PAGE_FIX_COUNT]->store(
-			static_cast<double>(page_info->fix_count)));
+			   page_info->fix_count, true));
 
 		if (page_info->hashed) {
 			OK(field_store_string(
-				fields[IDX_BUF_LRU_PAGE_HASHED], "YES"));
+				   fields[IDX_BUF_LRU_PAGE_HASHED], "YES"));
 		} else {
 			OK(field_store_string(
-				fields[IDX_BUF_LRU_PAGE_HASHED], "NO"));
+				   fields[IDX_BUF_LRU_PAGE_HASHED], "NO"));
 		}
 
 		OK(fields[IDX_BUF_LRU_PAGE_NEWEST_MOD]->store(
-			page_info->newest_mod, true));
+			   page_info->newest_mod, true));
 
 		OK(fields[IDX_BUF_LRU_PAGE_OLDEST_MOD]->store(
-			page_info->oldest_mod, true));
+			   page_info->oldest_mod, true));
 
 		OK(fields[IDX_BUF_LRU_PAGE_ACCESS_TIME]->store(
-			page_info->access_time));
+			   page_info->access_time, true));
 
 		fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->set_null();
 
@@ -5896,7 +5940,7 @@ i_s_innodb_buf_page_lru_fill(
 
 				OK(fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->store(
 					table_name,
-					static_cast<uint>(table_name_end - table_name),
+					static_cast<size_t>(table_name_end - table_name),
 					system_charset_info));
 				fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->set_notnull();
 
@@ -5909,14 +5953,14 @@ i_s_innodb_buf_page_lru_fill(
 		}
 
 		OK(fields[IDX_BUF_LRU_PAGE_NUM_RECS]->store(
-			page_info->num_recs));
+			   page_info->num_recs, true));
 
 		OK(fields[IDX_BUF_LRU_PAGE_DATA_SIZE]->store(
-			page_info->data_size));
+			   page_info->data_size, true));
 
 		OK(fields[IDX_BUF_LRU_PAGE_ZIP_SIZE]->store(
-			page_info->zip_ssize ?
-				 512 << page_info->zip_ssize : 0));
+			   page_info->zip_ssize ?
+			   512 << page_info->zip_ssize : 0, true));
 
 		state = static_cast<enum buf_page_state>(page_info->page_state);
 
@@ -5962,7 +6006,7 @@ i_s_innodb_buf_page_lru_fill(
 				      (page_info->is_old) ? "YES" : "NO"));
 
 		OK(fields[IDX_BUF_LRU_PAGE_FREE_CLOCK]->store(
-			page_info->freed_page_clock));
+			   page_info->freed_page_clock, true));
 
 		if (schema_table_store_record(thd, table)) {
 			mem_heap_free(heap);
@@ -6600,35 +6644,34 @@ i_s_dict_fill_sys_tablestats(
 				      "Initialized"));
 
 		OK(fields[SYS_TABLESTATS_NROW]->store(table->stat_n_rows,
-						      TRUE));
+						      true));
 
 		OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(
-			static_cast<double>(table->stat_clustered_index_size)));
+			   table->stat_clustered_index_size, true));
 
 		OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(
-			static_cast<double>(table->stat_sum_of_other_index_sizes)));
+			   table->stat_sum_of_other_index_sizes, true));
 
 		OK(fields[SYS_TABLESTATS_MODIFIED]->store(
-			static_cast<double>(table->stat_modified_counter)));
+			   table->stat_modified_counter, true));
 	} else {
 		OK(field_store_string(fields[SYS_TABLESTATS_INIT],
 				      "Uninitialized"));
 
-		OK(fields[SYS_TABLESTATS_NROW]->store(0, TRUE));
+		OK(fields[SYS_TABLESTATS_NROW]->store(0, true));
 
-		OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(0));
+		OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(0, true));
 
-		OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(0));
+		OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(0, true));
 
-		OK(fields[SYS_TABLESTATS_MODIFIED]->store(0));
+		OK(fields[SYS_TABLESTATS_MODIFIED]->store(0, true));
 	}
 
 	dict_table_stats_unlock(table, RW_S_LATCH);
 
-	OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc, TRUE));
+	OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc, true));
 
-	OK(fields[SYS_TABLESTATS_TABLE_REF_COUNT]->store(
-		static_cast<double>(ref_count)));
+	OK(fields[SYS_TABLESTATS_TABLE_REF_COUNT]->store(static_cast<double>(ref_count), true));
 
 	OK(schema_table_store_record(thd, table_to_fill));
 
@@ -6678,10 +6721,24 @@ i_s_sys_tables_fill_table_stats(
 			heap, rec, &table_rec,
 			DICT_TABLE_LOAD_FROM_CACHE, &mtr);
 
-		ref_count = table_rec->get_ref_count();
+		if (table_rec != NULL) {
+			ut_ad(err_msg == NULL);
+
+			ref_count = table_rec->get_ref_count();
+
+			/* Protect the dict_table_t object by incrementing
+			the reference count. */
+			table_rec->acquire();
+		}
+
 		mutex_exit(&dict_sys->mutex);
 
-		if (!err_msg) {
+		DBUG_EXECUTE_IF("test_sys_tablestats", {
+			if (strcmp("test/t1", table_rec->name.m_name) == 0 ) {
+				DEBUG_SYNC_C("dict_table_not_protected");
+			}});
+
+		if (table_rec != NULL) {
 			i_s_dict_fill_sys_tablestats(thd, table_rec, ref_count,
 						     tables->table);
 		} else {
@@ -6694,6 +6751,11 @@ i_s_sys_tables_fill_table_stats(
 
 		/* Get the next record */
 		mutex_enter(&dict_sys->mutex);
+
+		if (table_rec != NULL) {
+			table_rec->release();
+		}
+
 		mtr_start(&mtr);
 		rec = dict_getnext_system(&pcur, &mtr);
 	}
@@ -6876,9 +6938,9 @@ i_s_dict_fill_sys_indexes(
 
 	OK(field_store_index_name(fields[SYS_INDEX_NAME], index->name));
 
-	OK(fields[SYS_INDEX_ID]->store(longlong(index->id), TRUE));
+	OK(fields[SYS_INDEX_ID]->store(longlong(index->id), true));
 
-	OK(fields[SYS_INDEX_TABLE_ID]->store(longlong(table_id), TRUE));
+	OK(fields[SYS_INDEX_TABLE_ID]->store(longlong(table_id), true));
 
 	OK(fields[SYS_INDEX_TYPE]->store(index->type));
 
@@ -7128,9 +7190,9 @@ i_s_dict_fill_sys_columns(
 
 	if (dict_col_is_virtual(column)) {
 		ulint	pos = dict_create_v_col_pos(nth_v_col, column->ind);
-		OK(fields[SYS_COLUMN_POSITION]->store(pos));
+		OK(fields[SYS_COLUMN_POSITION]->store(pos, true));
 	} else {
-		OK(fields[SYS_COLUMN_POSITION]->store(column->ind));
+		OK(fields[SYS_COLUMN_POSITION]->store(column->ind, true));
 	}
 
 	OK(fields[SYS_COLUMN_MTYPE]->store(column->mtype));
@@ -7487,9 +7549,9 @@ struct st_maria_plugin	i_s_innodb_sys_virtual =
 	/* struct st_mysql_sys_var** */
 	STRUCT_FLD(system_vars, NULL),
 
-        /* Maria extension */
+	/* Maria extension */
 	STRUCT_FLD(version_info, INNODB_VERSION_STR),
-        STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_BETA),
+	STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_BETA),
 };
 /**  SYS_FIELDS  ***************************************************/
 /* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FIELDS */
@@ -7549,7 +7611,7 @@ i_s_dict_fill_sys_fields(
 
 	OK(field_store_string(fields[SYS_FIELD_NAME], field->name));
 
-	OK(fields[SYS_FIELD_POS]->store(static_cast<double>(pos)));
+	OK(fields[SYS_FIELD_POS]->store(static_cast<double>(pos), true));
 
 	OK(schema_table_store_record(thd, table_to_fill));
 
@@ -7997,7 +8059,7 @@ i_s_dict_fill_sys_foreign_cols(
 
 	OK(field_store_string(fields[SYS_FOREIGN_COL_REF_NAME], ref_col_name));
 
-	OK(fields[SYS_FOREIGN_COL_POS]->store(static_cast<double>(pos)));
+	OK(fields[SYS_FOREIGN_COL_POS]->store(pos, true));
 
 	OK(schema_table_store_record(thd, table_to_fill));
 
@@ -8246,15 +8308,6 @@ static ST_FIELD_INFO	innodb_sys_tablespaces_fields_info[] =
 	 STRUCT_FLD(old_name,           ""),
 	 STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
 
-#define SYS_TABLESPACES_COMPRESSION	11
-	{STRUCT_FLD(field_name,		"COMPRESSION"),
-	 STRUCT_FLD(field_length,	MAX_COMPRESSION_LEN + 1),
-	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
-	 STRUCT_FLD(value,		0),
-	 STRUCT_FLD(field_flags,	0),
-	 STRUCT_FLD(old_name,		""),
-	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
-
 	END_OF_ST_FIELD_INFO
 
 };
@@ -8329,7 +8382,17 @@ i_s_dict_fill_sys_tablespaces(
 	OK(field_store_string(fields[SYS_TABLESPACES_SPACE_TYPE],
 			      space_type));
 
-	char*	filename = fil_make_filepath(NULL, name, IBD, false);
+	char*	filepath = NULL;
+	if (FSP_FLAGS_HAS_DATA_DIR(flags)
+	    || FSP_FLAGS_GET_SHARED(flags)) {
+		mutex_enter(&dict_sys->mutex);
+		filepath = dict_get_first_path(space);
+		mutex_exit(&dict_sys->mutex);
+	}
+
+	if (filepath == NULL) {
+		filepath = fil_make_filepath(NULL, name, IBD, false);
+	}
 
 	os_file_stat_t	stat;
 	os_file_size_t	file;
@@ -8337,17 +8400,17 @@ i_s_dict_fill_sys_tablespaces(
 	memset(&file, 0xff, sizeof(file));
 	memset(&stat, 0x0, sizeof(stat));
 
-	if (filename != NULL) {
+	if (filepath != NULL) {
 
-		file = os_file_get_size(filename);
+		file = os_file_get_size(filepath);
 
 		/* Get the file system (or Volume) block size. */
-		dberr_t	err = os_file_get_status(filename, &stat, false, false);
+		dberr_t	err = os_file_get_status(filepath, &stat, false, false);
 
 		switch(err) {
 		case DB_FAIL:
 			ib::warn()
-				<< "File '" << filename << "', failed to get "
+				<< "File '" << filepath << "', failed to get "
 				<< "stats";
 			break;
 
@@ -8357,12 +8420,18 @@ i_s_dict_fill_sys_tablespaces(
 
 		default:
 			ib::error()
-				<< "File '" << filename << "' "
+				<< "File '" << filepath << "' "
 				<< ut_strerr(err);
 			break;
 		}
 
-		ut_free(filename);
+		ut_free(filepath);
+	}
+
+	if (file.m_total_size == static_cast<os_offset_t>(~0)) {
+		stat.block_size = 0;
+		file.m_total_size = 0;
+		file.m_alloc_size = 0;
 	}
 
 	OK(fields[SYS_TABLESPACES_FS_BLOCK_SIZE]->store(stat.block_size, true));
@@ -8371,12 +8440,6 @@ i_s_dict_fill_sys_tablespaces(
 
 	OK(fields[SYS_TABLESPACES_ALLOC_SIZE]->store(file.m_alloc_size, true));
 
-	Compression::Type	type = fil_get_compression(space);
-
-	OK(field_store_string(
-			fields[SYS_TABLESPACES_COMPRESSION],
-			Compression::to_string(type)));
-
 	OK(schema_table_store_record(thd, table_to_fill));
 
 	DBUG_RETURN(0);
@@ -9374,7 +9437,7 @@ i_s_innodb_mutexes_fill_table(
 
 	// mutex_enter(&mutex_list_mutex);
 
-	/* JAN: TODO: FIXME:
+#ifdef JAN_TODO_FIXME
 	for (mutex = UT_LIST_GET_FIRST(os_mutex_list); mutex != NULL;
 	     mutex = UT_LIST_GET_NEXT(list, mutex)) {
 		if (mutex->count_os_wait == 0) {
@@ -9408,7 +9471,7 @@ i_s_innodb_mutexes_fill_table(
 	}
 
 	mutex_exit(&mutex_list_mutex);
-	*/
+#endif /* JAN_TODO_FIXME */
 
 	mutex_enter(&rw_lock_list_mutex);
 
diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc
index bfdaefc..71aa7be 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.cc
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc
@@ -566,7 +566,7 @@ ibuf_init_at_db_start(void)
 
 	ibuf->index = dict_mem_index_create(
 		"innodb_change_buffer", "CLUST_IND",
-		IBUF_SPACE_ID, DICT_CLUSTERED | DICT_IBUF, 1);
+		IBUF_SPACE_ID, DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, 1);
 	ibuf->index->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
 	ibuf->index->table = dict_mem_table_create(
 		"innodb_change_buffer", IBUF_SPACE_ID, 1, 0, 0, 0);
@@ -828,6 +828,7 @@ ibuf_bitmap_get_map_page_func(
 		return NULL;
 	}
 
+
 	buf_block_dbg_add_level(block, SYNC_IBUF_BITMAP);
 
 	return(buf_block_get_frame(block));
@@ -2245,11 +2246,11 @@ ibuf_free_excess_pages(void)
 }
 
 #ifdef UNIV_DEBUG
-# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,vers,pages,n_stored) \
-	ibuf_get_merge_page_nos_func(contract,rec,mtr,ids,vers,pages,n_stored)
+# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,pages,n_stored) \
+	ibuf_get_merge_page_nos_func(contract,rec,mtr,ids,pages,n_stored)
 #else /* UNIV_DEBUG */
-# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,vers,pages,n_stored) \
-	ibuf_get_merge_page_nos_func(contract,rec,ids,vers, pages,n_stored)
+# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,pages,n_stored) \
+	ibuf_get_merge_page_nos_func(contract,rec,ids,pages,n_stored)
 #endif /* UNIV_DEBUG */
 
 /*********************************************************************//**
@@ -2272,9 +2273,6 @@ ibuf_get_merge_page_nos_func(
 	ulint*		page_nos,/*!< in/out: buffer for at least
 				IBUF_MAX_N_PAGES_MERGED many page numbers;
 				the page numbers are in an ascending order */
-	ib_uint64_t*	space_versions,/*!< in/out: tablespace version
-				timestamps; used to prevent reading in old
-				pages after DISCARD + IMPORT tablespace */
 	ulint*		n_stored)/*!< out: number of page numbers stored to
 				page_nos in this function */
 {
@@ -2403,8 +2401,6 @@ ibuf_get_merge_page_nos_func(
 				/ IBUF_MERGE_THRESHOLD)) {
 
 				space_ids[*n_stored] = prev_space_id;
-				space_versions[*n_stored]
-					= fil_space_get_version(prev_space_id);
 				page_nos[*n_stored] = prev_page_no;
 
 				(*n_stored)++;
@@ -2482,13 +2478,11 @@ ibuf_get_merge_pages(
 	ulint		limit,	/*!< in: max page numbers to read */
 	ulint*		pages,	/*!< out: pages read */
 	ulint*		spaces,	/*!< out: spaces read */
-	ib_uint64_t*	versions,/*!< out: space versions read */
 	ulint*		n_pages,/*!< out: number of pages read */
 	mtr_t*		mtr)	/*!< in: mini transaction */
 {
 	const rec_t*	rec;
 	ulint		volume = 0;
-	ib_uint64_t	version = fil_space_get_version(space);
 
 	ut_a(space != ULINT_UNDEFINED);
 
@@ -2503,7 +2497,6 @@ ibuf_get_merge_pages(
 		if (*n_pages == 0 || pages[*n_pages - 1] != page_no) {
 			spaces[*n_pages] = space;
 			pages[*n_pages] = page_no;
-			versions[*n_pages] = version;
 			++*n_pages;
 		}
 
@@ -2534,7 +2527,6 @@ ibuf_merge_pages(
 	ulint		sum_sizes;
 	ulint		page_nos[IBUF_MAX_N_PAGES_MERGED];
 	ulint		space_ids[IBUF_MAX_N_PAGES_MERGED];
-	ib_uint64_t	space_versions[IBUF_MAX_N_PAGES_MERGED];
 
 	*n_pages = 0;
 
@@ -2570,7 +2562,7 @@ ibuf_merge_pages(
 	sum_sizes = ibuf_get_merge_page_nos(TRUE,
 					    btr_pcur_get_rec(&pcur), &mtr,
 					    space_ids,
-					    page_nos, space_versions, n_pages);
+					    page_nos, n_pages);
 #if 0 /* defined UNIV_IBUF_DEBUG */
 	fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n",
 		sync, *n_pages, sum_sizes);
@@ -2579,7 +2571,7 @@ ibuf_merge_pages(
 	btr_pcur_close(&pcur);
 
 	buf_read_ibuf_merge_pages(
-		sync, space_ids, space_versions, page_nos, *n_pages);
+		sync, space_ids, page_nos, *n_pages);
 
 	return(sum_sizes + 1);
 }
@@ -2588,7 +2580,6 @@ ibuf_merge_pages(
 Contracts insert buffer trees by reading pages referring to space_id
 to the buffer pool.
 @returns number of pages merged.*/
-UNIV_INTERN
 ulint
 ibuf_merge_space(
 /*=============*/
@@ -2619,7 +2610,6 @@ ibuf_merge_space(
 	ulint		sum_sizes = 0;
 	ulint		pages[IBUF_MAX_N_PAGES_MERGED];
 	ulint		spaces[IBUF_MAX_N_PAGES_MERGED];
-	ib_uint64_t	versions[IBUF_MAX_N_PAGES_MERGED];
 
 	if (page_is_empty(btr_pcur_get_page(&pcur))) {
 		/* If a B-tree page is empty, it must be the root page
@@ -2634,11 +2624,10 @@ ibuf_merge_space(
 	} else {
 
 		sum_sizes = ibuf_get_merge_pages(
-				&pcur, space, IBUF_MAX_N_PAGES_MERGED,
-				&pages[0], &spaces[0], &versions[0], &n_pages,
-				&mtr);
+			&pcur, space, IBUF_MAX_N_PAGES_MERGED,
+			&pages[0], &spaces[0], &n_pages,
+			&mtr);
 		ib::info() << "Size of pages merged " << sum_sizes;
-
 	}
 
 	ibuf_mtr_commit(&mtr);
@@ -2646,18 +2635,16 @@ ibuf_merge_space(
 	btr_pcur_close(&pcur);
 
 	if (n_pages > 0) {
-
-#ifdef UNIV_DEBUG
 		ut_ad(n_pages <= UT_ARR_SIZE(pages));
 
+#ifdef UNIV_DEBUG
 		for (ulint i = 0; i < n_pages; ++i) {
 			ut_ad(spaces[i] == space);
-			ut_ad(i == 0 || versions[i] == versions[i - 1]);
 		}
 #endif /* UNIV_DEBUG */
 
 		buf_read_ibuf_merge_pages(
-			true, spaces, versions, pages, n_pages);
+			true, spaces, pages, n_pages);
 	}
 
 	return(n_pages);
@@ -2667,17 +2654,14 @@ ibuf_merge_space(
 @param[out]	n_pages		number of pages merged
 @param[in]	sync		whether the caller waits for
 the issued reads to complete
- at param[in]	space_id	tablespace for which to merge, or
-ULINT_UNDEFINED for all tablespaces
 @return a lower limit for the combined size in bytes of entries which
 will be merged from ibuf trees to the pages read, 0 if ibuf is
 empty */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
 ulint
 ibuf_merge(
 	ulint*		n_pages,
-	bool		sync,
-	ulint		space_id)
+	bool		sync)
 {
 	*n_pages = 0;
 
@@ -2692,10 +2676,8 @@ ibuf_merge(
 	} else if (ibuf_debug) {
 		return(0);
 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
-	} else if (space_id == ULINT_UNDEFINED) {
-		return(ibuf_merge_pages(n_pages, sync));
 	} else {
-		return(ibuf_merge_space(space_id));
+		return(ibuf_merge_pages(n_pages, sync));
 	}
 }
 
@@ -2718,15 +2700,12 @@ ibuf_contract(
 @param[in]	full		If true, do a full contraction based
 on PCT_IO(100). If false, the size of contract batch is determined
 based on the current size of the change buffer.
- at param[in]	space_id	tablespace for which to contract, or
-ULINT_UNDEFINED to contract for all tablespaces
 @return a lower limit for the combined size in bytes of entries which
 will be merged from ibuf trees to the pages read, 0 if ibuf is
 empty */
 ulint
 ibuf_merge_in_background(
-	bool	full,
-	ulint	space_id)
+	bool	full)
 {
 	ulint	sum_bytes	= 0;
 	ulint	sum_pages	= 0;
@@ -2734,7 +2713,7 @@ ibuf_merge_in_background(
 	ulint	n_pages;
 
 #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
-	if (srv_ibuf_disable_background_merge && space_id == ULINT_UNDEFINED) {
+	if (srv_ibuf_disable_background_merge) {
 		return(0);
 	}
 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
@@ -2771,7 +2750,7 @@ ibuf_merge_in_background(
 	while (sum_pages < n_pages) {
 		ulint	n_bytes;
 
-		n_bytes = ibuf_merge(&n_pag2, false, space_id);
+		n_bytes = ibuf_merge(&n_pag2, false);
 
 		if (n_bytes == 0) {
 			return(sum_bytes);
@@ -3383,7 +3362,7 @@ or clustered
 @param[in]	page_size	page size
 @param[in,out]	thr		query thread
 @return DB_SUCCESS, DB_STRONG_FAIL or other error */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
 dberr_t
 ibuf_insert_low(
 	ulint			mode,
@@ -3414,7 +3393,6 @@ ibuf_insert_low(
 	ibool		do_merge;
 	ulint		space_ids[IBUF_MAX_N_PAGES_MERGED];
 	ulint		page_nos[IBUF_MAX_N_PAGES_MERGED];
-	ib_uint64_t	space_versions[IBUF_MAX_N_PAGES_MERGED];
 	ulint		n_stored;
 	mtr_t		mtr;
 	mtr_t		bitmap_mtr;
@@ -3576,7 +3554,7 @@ ibuf_insert_low(
 			ibuf_get_merge_page_nos(FALSE,
 						btr_pcur_get_rec(&pcur), &mtr,
 						space_ids,
-						page_nos, space_versions, &n_stored);
+						page_nos, &n_stored);
 
 			goto fail_exit;
 		}
@@ -3711,7 +3689,7 @@ ibuf_insert_low(
 #ifdef UNIV_IBUF_DEBUG
 		ut_a(n_stored <= IBUF_MAX_N_PAGES_MERGED);
 #endif
-		buf_read_ibuf_merge_pages(false, space_ids, space_versions,
+		buf_read_ibuf_merge_pages(false, space_ids,
 					  page_nos, n_stored);
 	}
 
@@ -3973,7 +3951,7 @@ ibuf_insert_to_index_page(
 	ut_ad(!dict_index_is_online_ddl(index));// this is an ibuf_dummy index
 	ut_ad(ibuf_inside(mtr));
 	ut_ad(dtuple_check_typed(entry));
-	ut_ad(!buf_block_align(page)->index);
+	ut_ad(!block->index);
 	ut_ad(mtr->is_named_space(block->page.id.space()));
 
 	if (UNIV_UNLIKELY(dict_table_is_comp(index->table)
@@ -4813,7 +4791,6 @@ ibuf_merge_or_delete_for_page(
 	os_atomic_increment_ulint(&ibuf->n_merges, 1);
 	ibuf_add_ops(ibuf->n_merged_ops, mops);
 	ibuf_add_ops(ibuf->n_discarded_ops, dops);
-
 	if (space != NULL) {
 		fil_space_release(space);
 	}
diff --git a/storage/innobase/include/api0api.h b/storage/innobase/include/api0api.h
index 127f8e1..ec02feb 100644
--- a/storage/innobase/include/api0api.h
+++ b/storage/innobase/include/api0api.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2012, 2016, 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
@@ -1030,4 +1030,11 @@ ib_ut_strerr(
 /*=========*/
 	ib_err_t	num);		/*!< in: error number */
 
+/** Check the table whether it contains virtual columns.
+ at param[in]	crsr	InnoDB Cursor
+ at return true if table contains virtual column else false. */
+ib_bool_t
+ib_is_virtual_table(
+        ib_crsr_t	crsr);
+
 #endif /* api0api_h */
diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h
index e350e01..c177f23 100644
--- a/storage/innobase/include/btr0btr.h
+++ b/storage/innobase/include/btr0btr.h
@@ -179,7 +179,7 @@ dberr_t
 btr_root_adjust_on_import(
 /*======================*/
 	const dict_index_t*	index)	/*!< in: index tree */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /**************************************************************//**
 Gets the height of the B-tree (the level of the root, when the leaf
@@ -191,7 +191,7 @@ btr_height_get(
 /*===========*/
 	dict_index_t*	index,	/*!< in: index tree */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Gets a buffer page and declares its latching order level.
 @param[in]	page_id	page id
@@ -254,7 +254,7 @@ index_id_t
 btr_page_get_index_id(
 /*==================*/
 	const page_t*	page)	/*!< in: index page */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 #ifndef UNIV_HOTBACKUP
 /********************************************************//**
 Gets the node level field in an index page.
@@ -264,7 +264,7 @@ ulint
 btr_page_get_level_low(
 /*===================*/
 	const page_t*	page)	/*!< in: index page */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 #define btr_page_get_level(page, mtr) btr_page_get_level_low(page)
 /********************************************************//**
 Gets the next index page number.
@@ -275,7 +275,7 @@ btr_page_get_next(
 /*==============*/
 	const page_t*	page,	/*!< in: index page */
 	mtr_t*		mtr)	/*!< in: mini-transaction handle */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /********************************************************//**
 Gets the previous index page number.
 @return prev page number */
@@ -285,7 +285,7 @@ btr_page_get_prev(
 /*==============*/
 	const page_t*	page,	/*!< in: index page */
 	mtr_t*		mtr)	/*!< in: mini-transaction handle */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**************************************************************//**
 Releases the latch on a leaf page and bufferunfixes it. */
 UNIV_INLINE
@@ -310,7 +310,7 @@ btr_node_ptr_get_child_page_no(
 /*===========================*/
 	const rec_t*	rec,	/*!< in: node pointer record */
 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Create the root node for a new index tree.
 @param[in]	type			type of the index
@@ -374,7 +374,7 @@ btr_root_raise_and_insert(
 	const dtuple_t*	tuple,	/*!< in: tuple to insert */
 	ulint		n_ext,	/*!< in: number of externally stored columns */
 	mtr_t*		mtr)	/*!< in: mtr */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /*************************************************************//**
 Reorganizes an index page.
 
@@ -399,7 +399,7 @@ btr_page_reorganize_low(
 	page_cur_t*	cursor,	/*!< in/out: page cursor */
 	dict_index_t*	index,	/*!< in: the index tree of the page */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /*************************************************************//**
 Reorganizes an index page.
 
@@ -429,7 +429,7 @@ btr_page_get_split_rec_to_left(
 	rec_t**		split_rec)/*!< out: if split recommended,
 				the first record on upper half page,
 				or NULL if tuple should be first */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /*************************************************************//**
 Decides if the page should be split at the convergence point of
 inserts converging to right.
@@ -441,7 +441,7 @@ btr_page_get_split_rec_to_right(
 	rec_t**		split_rec)/*!< out: if split recommended,
 				the first record on upper half page,
 				or NULL if tuple should be first */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*************************************************************//**
 Splits an index page to halves and inserts the tuple. It is assumed
@@ -465,7 +465,7 @@ btr_page_split_and_insert(
 	const dtuple_t*	tuple,	/*!< in: tuple to insert */
 	ulint		n_ext,	/*!< in: number of externally stored columns */
 	mtr_t*		mtr)	/*!< in: mtr */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /*******************************************************//**
 Inserts a data tuple to a tree on a non-leaf level. It is assumed
 that mtr holds an x-latch on the tree. */
@@ -478,8 +478,7 @@ btr_insert_on_non_leaf_level_func(
 	dtuple_t*	tuple,	/*!< in: the record to be inserted */
 	const char*	file,	/*!< in: file name */
 	ulint		line,	/*!< in: line where called */
-	mtr_t*		mtr)	/*!< in: mtr */
-	MY_ATTRIBUTE((nonnull(4,5)));
+	mtr_t*		mtr);	/*!< in: mtr */
 # define btr_insert_on_non_leaf_level(f,i,l,t,m)			\
 	btr_insert_on_non_leaf_level_func(f,i,l,t,__FILE__,__LINE__,m)
 #endif /* !UNIV_HOTBACKUP */
@@ -511,7 +510,7 @@ btr_check_node_ptr(
 	dict_index_t*	index,	/*!< in: index tree */
 	buf_block_t*	block,	/*!< in: index page */
 	mtr_t*		mtr)	/*!< in: mtr */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 #endif /* UNIV_DEBUG */
 /*************************************************************//**
 Tries to merge the page first to the left immediate brother if such a
@@ -543,8 +542,7 @@ btr_discard_page(
 /*=============*/
 	btr_cur_t*	cursor,	/*!< in: cursor on the page to discard: not on
 				the root page */
-	mtr_t*		mtr)	/*!< in: mtr */
-	MY_ATTRIBUTE((nonnull));
+	mtr_t*		mtr);	/*!< in: mtr */
 #endif /* !UNIV_HOTBACKUP */
 /****************************************************************//**
 Parses the redo log record for setting an index record as the predefined
@@ -571,7 +569,7 @@ btr_parse_page_reorganize(
 	bool		compressed,/*!< in: true if compressed page */
 	buf_block_t*	block,	/*!< in: page to be reorganized, or NULL */
 	mtr_t*		mtr)	/*!< in: mtr or NULL */
-	MY_ATTRIBUTE((nonnull(1,2,3), warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 #ifndef UNIV_HOTBACKUP
 /**************************************************************//**
 Gets the number of pages in a B-tree.
@@ -583,7 +581,7 @@ btr_get_size(
 	ulint		flag,	/*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction where index
 				is s-latched */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**************************************************************//**
 Gets the number of reserved and used pages in a B-tree.
 @return	number of pages reserved, or ULINT_UNDEFINED if the index
@@ -620,7 +618,7 @@ btr_page_alloc(
 	mtr_t*		init_mtr)	/*!< in/out: mini-transaction
 					for x-latching and initializing
 					the page */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**************************************************************//**
 Frees a file page used in an index tree. NOTE: cannot free field external
 storage pages because the page must contain info on its level. */
@@ -653,7 +651,7 @@ btr_page_free_low(
 	ulint		level,	/*!< in: page level (ULINT_UNDEFINED=BLOB) */
 	bool		blob,   /*!< in: blob page */
 	mtr_t*		mtr)	/*!< in: mtr */
-	__attribute__((nonnull));
+	MY_ATTRIBUTE((nonnull(1,2)));
 /**************************************************************//**
 Gets the root node of a tree and x- or s-latches it.
 @return root page, x- or s-latched */
@@ -695,7 +693,6 @@ btr_page_reorganize_block(
 #ifdef UNIV_BTR_PRINT
 /*************************************************************//**
 Prints size info of a B-tree. */
-UNIV_INTERN
 void
 btr_print_size(
 /*===========*/
@@ -703,7 +700,6 @@ btr_print_size(
 	MY_ATTRIBUTE((nonnull));
 /**************************************************************//**
 Prints directories and other info of all nodes in the index. */
-UNIV_INTERN
 void
 btr_print_index(
 /*============*/
@@ -724,18 +720,17 @@ btr_index_rec_validate(
 	ibool			dump_on_error)	/*!< in: TRUE if the function
 						should print hex dump of record
 						and page on error */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**************************************************************//**
 Checks the consistency of an index tree.
 @return	DB_SUCCESS if ok, error code if not */
-UNIV_INTERN
 dberr_t
 btr_validate_index(
 /*===============*/
 	dict_index_t*	index,	/*!< in: index */
 	const trx_t*	trx,	/*!< in: transaction or 0 */
 	bool		lockout)/*!< in: true if X-latch index is intended */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*************************************************************//**
 Removes a page from the level list of pages. */
diff --git a/storage/innobase/include/btr0bulk.h b/storage/innobase/include/btr0bulk.h
index 64ffa89..a1887c3 100644
--- a/storage/innobase/include/btr0bulk.h
+++ b/storage/innobase/include/btr0bulk.h
@@ -260,7 +260,7 @@ class PageBulk
 	FlushObserver*	m_flush_observer;
 
 	/** Operation result DB_SUCCESS or error code */
-	dberr_t         m_err;
+	dberr_t		m_err;
 };
 
 typedef std::vector<PageBulk*, ut_allocator<PageBulk*> >
diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h
index 659944f..1265903 100644
--- a/storage/innobase/include/btr0sea.h
+++ b/storage/innobase/include/btr0sea.h
@@ -328,6 +328,13 @@ extern rw_lock_t**		btr_search_latches;
 /** The adaptive hash index */
 extern btr_search_sys_t*	btr_search_sys;
 
+#ifdef UNIV_SEARCH_PERF_STAT
+/** Number of successful adaptive hash index lookups */
+extern ulint	btr_search_n_succ;
+/** Number of failed adaptive hash index lookups */
+extern ulint	btr_search_n_hash_fail;
+#endif /* UNIV_SEARCH_PERF_STAT */
+
 /** After change in n_fields or n_bytes in info, this many rounds are waited
 before starting the hash analysis again: this is to save CPU time when there
 is no hope in building a hash index. */
diff --git a/storage/innobase/include/btr0sea.ic b/storage/innobase/include/btr0sea.ic
index 4fd7681..5f7c39b 100644
--- a/storage/innobase/include/btr0sea.ic
+++ b/storage/innobase/include/btr0sea.ic
@@ -200,7 +200,8 @@ btr_get_search_latch(const dict_index_t* index)
 {
 	ut_ad(index != NULL);
 
-	ulint	ifold = ut_fold_ulint_pair(index->id, index->space);
+	ulint	ifold = ut_fold_ulint_pair(static_cast<ulint>(index->id),
+					   static_cast<ulint>(index->space));
 
 	return(btr_search_latches[ifold % btr_ahi_parts]);
 }
@@ -215,7 +216,8 @@ btr_get_search_table(const dict_index_t* index)
 {
 	ut_ad(index != NULL);
 
-	ulint	ifold = ut_fold_ulint_pair(index->id, index->space);
+	ulint	ifold = ut_fold_ulint_pair(static_cast<ulint>(index->id),
+					   static_cast<ulint>(index->space));
 
 	return(btr_search_sys->hash_tables[ifold % btr_ahi_parts]);
 }
diff --git a/storage/innobase/include/btr0types.h b/storage/innobase/include/btr0types.h
index 734b33e..19c2198 100644
--- a/storage/innobase/include/btr0types.h
+++ b/storage/innobase/include/btr0types.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2016, 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
diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
index 6e147ce..c4bc107 100644
--- a/storage/innobase/include/buf0buf.h
+++ b/storage/innobase/include/buf0buf.h
@@ -109,6 +109,9 @@ extern buf_block_t*	back_block2;	/*!< second block, for page reorganize */
 #endif /* !UNIV_HOTBACKUP */
 #endif /* !UNIV_INNOCHECKSUM */
 
+/** Magic value to use instead of checksums when they are disabled */
+#define BUF_NO_CHECKSUM_MAGIC 0xDEADBEEFUL
+
 #ifndef UNIV_INNOCHECKSUM
 /** @brief States of a control block
 @see buf_page_t
@@ -679,7 +682,7 @@ ulint
 buf_page_get_freed_page_clock(
 /*==========================*/
 	const buf_page_t*	bpage)	/*!< in: block */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /********************************************************************//**
 Reads the freed_page_clock of a buffer block.
 @return freed_page_clock */
@@ -688,7 +691,7 @@ ulint
 buf_block_get_freed_page_clock(
 /*===========================*/
 	const buf_block_t*	block)	/*!< in: block */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /********************************************************************//**
 Tells if a block is still close enough to the MRU end of the LRU list
@@ -834,8 +837,7 @@ buf_page_is_corrupted(
 	bool			is_log_enabled,
 	FILE*			log_file
 #endif /* UNIV_INNOCHECKSUM */
-) __attribute__((warn_unused_result));
-
+) MY_ATTRIBUTE((warn_unused_result));
 #ifndef UNIV_INNOCHECKSUM
 #ifndef UNIV_HOTBACKUP
 /**********************************************************************//**
@@ -857,7 +859,7 @@ ulint
 buf_block_get_lock_hash_val(
 /*========================*/
 	const buf_block_t*	block)	/*!< in: block */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 #ifdef UNIV_DEBUG
 /*********************************************************************//**
 Finds a block in the buffer pool that points to a
@@ -1039,7 +1041,7 @@ enum buf_page_state
 buf_block_get_state(
 /*================*/
 	const buf_block_t*	block)	/*!< in: pointer to the control block */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Sets the state of a block. */
 UNIV_INLINE
@@ -1064,7 +1066,7 @@ ibool
 buf_page_in_file(
 /*=============*/
 	const buf_page_t*	bpage)	/*!< in: pointer to control block */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 #ifndef UNIV_HOTBACKUP
 /*********************************************************************//**
 Determines if a block should be on unzip_LRU list.
@@ -1074,7 +1076,7 @@ ibool
 buf_page_belongs_to_unzip_LRU(
 /*==========================*/
 	const buf_page_t*	bpage)	/*!< in: pointer to control block */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*********************************************************************//**
 Gets the mutex of a block.
@@ -1084,7 +1086,7 @@ BPageMutex*
 buf_page_get_mutex(
 /*===============*/
 	const buf_page_t*	bpage)	/*!< in: pointer to control block */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*********************************************************************//**
 Get the flush type of a page.
@@ -1094,7 +1096,7 @@ buf_flush_t
 buf_page_get_flush_type(
 /*====================*/
 	const buf_page_t*	bpage)	/*!< in: buffer page */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Set the flush type of a page. */
 UNIV_INLINE
@@ -1121,7 +1123,7 @@ enum buf_io_fix
 buf_page_get_io_fix(
 /*================*/
 	const buf_page_t*	bpage)	/*!< in: pointer to the control block */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Gets the io_fix state of a block.
 @return io_fix state */
@@ -1130,7 +1132,7 @@ enum buf_io_fix
 buf_block_get_io_fix(
 /*================*/
 	const buf_block_t*	block)	/*!< in: pointer to the control block */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Sets the io_fix state of a block. */
 UNIV_INLINE
@@ -1176,7 +1178,7 @@ ibool
 buf_page_can_relocate(
 /*==================*/
 	const buf_page_t*	bpage)	/*!< control block being relocated */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*********************************************************************//**
 Determine if a block has been flagged old.
@@ -1186,7 +1188,7 @@ ibool
 buf_page_is_old(
 /*============*/
 	const buf_page_t*	bpage)	/*!< in: control block */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Flag a block old. */
 UNIV_INLINE
@@ -1203,7 +1205,7 @@ unsigned
 buf_page_is_accessed(
 /*=================*/
 	const buf_page_t*	bpage)	/*!< in: control block */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Flag a block accessed. */
 UNIV_INLINE
@@ -1222,7 +1224,7 @@ buf_block_t*
 buf_page_get_block(
 /*===============*/
 	buf_page_t*	bpage)	/*!< in: control block, or NULL */
-	MY_ATTRIBUTE((pure));
+	MY_ATTRIBUTE((warn_unused_result));
 #endif /* !UNIV_HOTBACKUP */
 #ifdef UNIV_DEBUG
 /*********************************************************************//**
@@ -1233,7 +1235,7 @@ buf_frame_t*
 buf_block_get_frame(
 /*================*/
 	const buf_block_t*	block)	/*!< in: pointer to the control block */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 #else /* UNIV_DEBUG */
 # define buf_block_get_frame(block) (block)->frame
 #endif /* UNIV_DEBUG */
@@ -1244,13 +1246,14 @@ if applicable. */
 #define buf_block_get_page_zip(block) \
 	((block)->page.zip.data ? &(block)->page.zip : NULL)
 #ifndef UNIV_HOTBACKUP
-/*******************************************************************//**
-Gets the block to whose frame the pointer is pointing to.
+
+/** Get a buffer block from an adaptive hash index pointer.
+This function does not return if the block is not identified.
+ at param[in]	ptr	pointer to within a page frame
 @return pointer to block, never NULL */
 buf_block_t*
-buf_block_align(
-/*============*/
-	const byte*	ptr);	/*!< in: pointer to a frame */
+buf_block_from_ahi(const byte* ptr);
+
 /********************************************************************//**
 Find out if a pointer belongs to a buf_block_t. It can be a pointer to
 the buf_block_t itself or a member of it
@@ -1271,18 +1274,6 @@ buf_pointer_is_block_field(
 #define buf_pool_is_block_lock(l)			\
 	buf_pointer_is_block_field((const void*)(l))
 
-#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
-/*********************************************************************//**
-Gets the compressed page descriptor corresponding to an uncompressed page
-if applicable.
- at return compressed page descriptor, or NULL */
-UNIV_INLINE
-const page_zip_des_t*
-buf_frame_get_page_zip(
-/*===================*/
-	const byte*	ptr);	/*!< in: pointer to the page */
-#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
-
 /** Inits a page for read to the buffer buf_pool. If the page is
 (1) already in buf_pool, or
 (2) if we specify to read only ibuf pages and the page is not an ibuf page, or
@@ -1322,7 +1313,7 @@ ulint
 buf_pool_index(
 /*===========*/
 	const buf_pool_t*	buf_pool)	/*!< in: buffer pool */
-	MY_ATTRIBUTE((nonnull, const));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************************//**
 Returns the buffer pool instance given a page instance
 @return buf_pool */
@@ -1465,7 +1456,7 @@ buf_page_t*
 buf_pool_watch_set(
 	const page_id_t&	page_id,
 	rw_lock_t**		hash_lock)
-	MY_ATTRIBUTE((warn_unused_result));
+MY_ATTRIBUTE((warn_unused_result));
 
 /** Stop watching if the page has been read in.
 buf_pool_watch_set(space,offset) must have returned NULL before.
@@ -1482,7 +1473,7 @@ has returned NULL and before invoking buf_pool_watch_unset(space,offset).
 ibool
 buf_pool_watch_occurred(
 	const page_id_t&	page_id)
-	MY_ATTRIBUTE((warn_unused_result));
+MY_ATTRIBUTE((warn_unused_result));
 
 /********************************************************************//**
 Get total buffer pool statistics. */
diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic
index bd75c7a..bf77997 100644
--- a/storage/innobase/include/buf0buf.ic
+++ b/storage/innobase/include/buf0buf.ic
@@ -1,8 +1,8 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
 Copyright (c) 2008, Google Inc.
-Copyright (c) 2014, 2015, MariaDB Corporation.
+Copyright (c) 2014, 2016, MariaDB Corporation.
 
 Portions of this file contain modifications contributed and copyrighted by
 Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -50,6 +50,11 @@ struct buf_chunk_t{
 					alloc method and later passed to the
 					deallocate method. */
 	buf_block_t*	blocks;		/*!< array of buffer control blocks */
+
+	/** Get the size of 'mem' in bytes. */
+	size_t	mem_size() const {
+		return(mem_pfx.m_size);
+	}
 };
 
 /*********************************************************************//**
@@ -315,7 +320,8 @@ buf_page_set_state(
 		break;
 	case BUF_BLOCK_FILE_PAGE:
 		if (!(state == BUF_BLOCK_NOT_USED
-	              || state == BUF_BLOCK_REMOVE_HASH)) {
+	              || state == BUF_BLOCK_REMOVE_HASH
+		      || state == BUF_BLOCK_FILE_PAGE)) {
 			const char *old_state_name = buf_get_state_name((buf_block_t*)bpage);
 			bpage->state = state;
 
@@ -326,10 +332,11 @@ buf_page_set_state(
 				old_state_name,
 				state,
 				buf_get_state_name((buf_block_t*)bpage));
+			ut_a(state == BUF_BLOCK_NOT_USED
+				|| state == BUF_BLOCK_REMOVE_HASH
+				|| state == BUF_BLOCK_FILE_PAGE);
 		}
 
-		ut_a(state == BUF_BLOCK_NOT_USED
-		     || state == BUF_BLOCK_REMOVE_HASH);
 		break;
 	case BUF_BLOCK_REMOVE_HASH:
 		ut_a(state == BUF_BLOCK_MEMORY);
@@ -770,23 +777,6 @@ buf_frame_align(
         return(frame);
 }
 
-#ifndef UNIV_HOTBACKUP
-#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
-/*********************************************************************//**
-Gets the compressed page descriptor corresponding to an uncompressed page
-if applicable.
- at return compressed page descriptor, or NULL */
-UNIV_INLINE
-const page_zip_des_t*
-buf_frame_get_page_zip(
-/*===================*/
-	const byte*	ptr)	/*!< in: pointer to the page */
-{
-	return(buf_block_get_page_zip(buf_block_align(ptr)));
-}
-#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
-#endif /* !UNIV_HOTBACKUP */
-
 /**********************************************************************//**
 Gets the space id, page offset, and byte offset within page of a
 pointer pointing to a buffer frame containing a file page. */
@@ -1421,6 +1411,25 @@ buf_get_nth_chunk_block(
 	return(chunk->blocks);
 }
 
+/********************************************************************//**
+Get buf frame. */
+UNIV_INLINE
+void *
+buf_page_get_frame(
+/*===============*/
+	const buf_page_t*	bpage) /*!< in: buffer pool page */
+{
+	/* In encryption/compression buffer pool page may contain extra
+	buffer where result is stored. */
+	if (bpage->slot && bpage->slot->out_buf) {
+		return bpage->slot->out_buf;
+	} else if (bpage->zip.data) {
+		return bpage->zip.data;
+	} else {
+		return ((buf_block_t*) bpage)->frame;
+	}
+}
+
 /** Verify the possibility that a stored page is not in buffer pool.
 @param[in]	withdraw_clock	withdraw clock when stored the page
 @retval true	if the page might be relocated */
@@ -1452,22 +1461,4 @@ buf_pool_size_align(
 	}
 }
 
-/********************************************************************//**
-Get buf frame. */
-UNIV_INLINE
-void *
-buf_page_get_frame(
-/*===============*/
-	const buf_page_t*	bpage) /*!< in: buffer pool page */
-{
-	/* In encryption/compression buffer pool page may contain extra
-	buffer where result is stored. */
-	if (bpage->slot && bpage->slot->out_buf) {
-		return bpage->slot->out_buf;
-	} else if (bpage->zip.data) {
-		return bpage->zip.data;
-	} else {
-		return ((buf_block_t*) bpage)->frame;
-	}
-}
 #endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/include/buf0checksum.h b/storage/innobase/include/buf0checksum.h
index 684c378..9405251 100644
--- a/storage/innobase/include/buf0checksum.h
+++ b/storage/innobase/include/buf0checksum.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, 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
@@ -30,9 +30,6 @@ Created Aug 11, 2011 Vasil Dimov
 
 #include "buf0types.h"
 
-/** Magic value to use instead of checksums when they are disabled */
-#define BUF_NO_CHECKSUM_MAGIC 0xDEADBEEFUL
-
 /** Calculates the CRC32 checksum of a page. The value is stored to the page
 when it is written to a file and also checked for a match when reading from
 the file. When reading we allow both normal CRC32 and CRC-legacy-big-endian
@@ -70,6 +67,7 @@ buf_calc_page_old_checksum(
 /*=======================*/
 	const byte*	page);	/*!< in: buffer page */
 
+
 /********************************************************************//**
 Return a printable string describing the checksum algorithm.
 @return algorithm name */
@@ -79,5 +77,6 @@ buf_checksum_algorithm_name(
 	srv_checksum_algorithm_t	algo);	/*!< in: algorithm */
 
 extern ulong	srv_checksum_algorithm;
+extern bool	legacy_big_endian_checksum;
 
 #endif /* buf0checksum_h */
diff --git a/storage/innobase/include/buf0dblwr.h b/storage/innobase/include/buf0dblwr.h
index 1f8f23e..eb13c3b 100644
--- a/storage/innobase/include/buf0dblwr.h
+++ b/storage/innobase/include/buf0dblwr.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, 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
@@ -43,7 +43,7 @@ extern ibool		buf_dblwr_being_created;
 Creates the doublewrite buffer to a new InnoDB installation. The header of the
 doublewrite buffer is placed on the trx system header page.
 @return true if successful, false if not. */
-__attribute__((warn_unused_result))
+MY_ATTRIBUTE((warn_unused_result))
 bool
 buf_dblwr_create(void);
 /*==================*/
diff --git a/storage/innobase/include/buf0flu.h b/storage/innobase/include/buf0flu.h
index 1d38c67..4008379 100644
--- a/storage/innobase/include/buf0flu.h
+++ b/storage/innobase/include/buf0flu.h
@@ -36,14 +36,18 @@ Created 11/5/1995 Heikki Tuuri
 /** Flag indicating if the page_cleaner is in active state. */
 extern bool buf_page_cleaner_is_active;
 
-/** Event to synchronise with the flushing. */
-extern os_event_t	buf_flush_event;
+#ifdef UNIV_DEBUG
 
-class ut_stage_alter_t;
+/** Value of MySQL global variable used to disable page cleaner. */
+extern my_bool		innodb_page_cleaner_disabled_debug;
+
+#endif /* UNIV_DEBUG */
 
 /** Event to synchronise with the flushing. */
 extern os_event_t	buf_flush_event;
 
+class ut_stage_alter_t;
+
 /** Handled page counters for a single flush */
 struct flush_counters_t {
 	ulint	flushed;	/*!< number of dirty pages flushed */
@@ -101,7 +105,7 @@ buf_flush_page_try(
 /*===============*/
 	buf_pool_t*	buf_pool,	/*!< in/out: buffer pool instance */
 	buf_block_t*	block)		/*!< in/out: buffer control block */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 # endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
 /** Do flushing batch of a given type.
 NOTE: The calling thread is not allowed to own any latches on pages!
@@ -124,6 +128,7 @@ buf_flush_do_batch(
 	lsn_t			lsn_limit,
 	flush_counters_t*	n);
 
+
 /** This utility flushes dirty blocks from the end of the flush list of all
 buffer pool instances.
 NOTE: The calling thread is not allowed to own any latches on pages!
@@ -216,6 +221,22 @@ buf_flush_ready_for_replace(
 /*========================*/
 	buf_page_t*	bpage);	/*!< in: buffer control block, must be
 				buf_page_in_file(bpage) and in the LRU list */
+
+#ifdef UNIV_DEBUG
+/** Disables page cleaner threads (coordinator and workers).
+It's used by: SET GLOBAL innodb_page_cleaner_disabled_debug = 1 (0).
+ at param[in]	thd		thread handle
+ at param[in]	var		pointer to system variable
+ at param[out]	var_ptr		where the formal string goes
+ at param[in]	save		immediate result from check function */
+void
+buf_flush_page_cleaner_disabled_debug_update(
+	THD*				thd,
+	struct st_mysql_sys_var*	var,
+	void*				var_ptr,
+	const void*			save);
+#endif /* UNIV_DEBUG */
+
 /******************************************************************//**
 page_cleaner thread tasked with flushing dirty pages from the buffer
 pools. As of now we'll have only one coordinator of this thread.
diff --git a/storage/innobase/include/buf0rea.h b/storage/innobase/include/buf0rea.h
index f2ec11f..9c97a51 100644
--- a/storage/innobase/include/buf0rea.h
+++ b/storage/innobase/include/buf0rea.h
@@ -126,13 +126,6 @@ buf_read_ibuf_merge_pages(
 					to get read in, before this
 					function returns */
 	const ulint*	space_ids,	/*!< in: array of space ids */
-	const ib_uint64_t* space_versions,/*!< in: the spaces must have
-					this version number
-					(timestamp), otherwise we
-					discard the read; we use this
-					to cancel reads if DISCARD +
-					IMPORT may have changed the
-					tablespace size */
 	const ulint*	page_nos,	/*!< in: array of page numbers
 					to read, with the highest page
 					number the last in the
diff --git a/storage/innobase/include/data0data.h b/storage/innobase/include/data0data.h
index 24b0a79..5537d70 100644
--- a/storage/innobase/include/data0data.h
+++ b/storage/innobase/include/data0data.h
@@ -70,8 +70,8 @@ void
 dfield_set_type(
 /*============*/
 	dfield_t*	field,	/*!< in: SQL data field */
-	const dtype_t*	type)	/*!< in: pointer to data type struct */
-	MY_ATTRIBUTE((nonnull));
+	const dtype_t*	type);	/*!< in: pointer to data type struct */
+
 /*********************************************************************//**
 Gets length of field data.
 @return length of data; UNIV_SQL_NULL if SQL null data */
@@ -116,6 +116,23 @@ dfield_set_ext(
 /*===========*/
 	dfield_t*	field)	/*!< in/out: field */
 	MY_ATTRIBUTE((nonnull));
+
+/** Gets spatial status for "external storage"
+ at param[in,out]	field		field */
+UNIV_INLINE
+spatial_status_t
+dfield_get_spatial_status(
+	const dfield_t*	field);
+
+/** Sets spatial status for "external storage"
+ at param[in,out]	field		field
+ at param[in]	spatial_status	spatial status */
+UNIV_INLINE
+void
+dfield_set_spatial_status(
+	dfield_t*		field,
+	spatial_status_t	spatial_status);
+
 /*********************************************************************//**
 Sets pointer to the data and length in a field. */
 UNIV_INLINE
@@ -134,7 +151,7 @@ dfield_write_mbr(
 /*=============*/
 	dfield_t*	field,	/*!< in: field */
 	const double*	mbr)	/*!< in: data */
-	__attribute__((nonnull(1)));
+	MY_ATTRIBUTE((nonnull(1)));
 /*********************************************************************//**
 Sets a data field to SQL NULL. */
 UNIV_INLINE
@@ -159,8 +176,8 @@ void
 dfield_copy_data(
 /*=============*/
 	dfield_t*	field1,		/*!< out: field to copy to */
-	const dfield_t*	field2)	/*!< in: field to copy from */
-	MY_ATTRIBUTE((nonnull));
+	const dfield_t*	field2);	/*!< in: field to copy from */
+
 /*********************************************************************//**
 Copies a data field to another. */
 UNIV_INLINE
@@ -408,7 +425,7 @@ int
 dtuple_coll_cmp(
 	const dtuple_t*	tuple1,
 	const dtuple_t*	tuple2)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /** Fold a prefix given as the number of fields of a tuple.
 @param[in]	tuple		index record
 @param[in]	n_fields	number of complete fields to fold
@@ -422,7 +439,7 @@ dtuple_fold(
 	ulint		n_fields,
 	ulint		n_bytes,
 	index_id_t	tree_id)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /*******************************************************************//**
 Sets types of fields binary in a tuple. */
 UNIV_INLINE
@@ -544,7 +561,7 @@ dtuple_convert_big_rec(
 	dtuple_t*	entry,	/*!< in/out: index entry */
 	ulint*		n_ext)	/*!< in/out: number of
 				externally stored columns */
-	MY_ATTRIBUTE((nonnull(1,4), malloc, warn_unused_result));
+	MY_ATTRIBUTE((malloc, warn_unused_result));
 /**************************************************************//**
 Puts back to entry the data stored in vector. Note that to ensure the
 fields in entry can accommodate the data, vector must have been created
@@ -572,7 +589,10 @@ dtuple_big_rec_free(
 /** Structure for an SQL data field */
 struct dfield_t{
 	void*		data;	/*!< pointer to data */
-	unsigned	ext;	/*!< TRUE=externally stored, FALSE=local */
+	unsigned	ext:1;	/*!< TRUE=externally stored, FALSE=local */
+	unsigned	spatial_status:2;
+				/*!< spatial status of externally stored field
+				in undo log for purge */
 	unsigned	len;	/*!< data length; UNIV_SQL_NULL if SQL null */
 	dtype_t		type;	/*!< type of data */
 
diff --git a/storage/innobase/include/data0data.ic b/storage/innobase/include/data0data.ic
index c6c155c..dc51735 100644
--- a/storage/innobase/include/data0data.ic
+++ b/storage/innobase/include/data0data.ic
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1994, 2016, 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
@@ -157,6 +157,34 @@ dfield_set_ext(
 	field->ext = 1;
 }
 
+/** Gets spatial status for "external storage"
+ at param[in,out]	field		field */
+UNIV_INLINE
+spatial_status_t
+dfield_get_spatial_status(
+	const dfield_t*	field)
+{
+	ut_ad(field);
+	ut_ad(dfield_is_ext(field));
+
+	return(static_cast<spatial_status_t>(field->spatial_status));
+}
+
+/** Sets spatial status for "external storage"
+ at param[in,out]	field		field
+ at param[in]	spatial_status	spatial status */
+UNIV_INLINE
+void
+dfield_set_spatial_status(
+	dfield_t*		field,
+	spatial_status_t	spatial_status)
+{
+	ut_ad(field);
+	ut_ad(dfield_is_ext(field));
+
+	field->spatial_status = spatial_status;
+}
+
 /*********************************************************************//**
 Sets pointer to the data and length in a field. */
 UNIV_INLINE
@@ -227,6 +255,7 @@ dfield_copy_data(
 	field1->data = field2->data;
 	field1->len = field2->len;
 	field1->ext = field2->ext;
+	field1->spatial_status = field2->spatial_status;
 }
 
 /*********************************************************************//**
diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h
index 5297d6b..32f9117 100644
--- a/storage/innobase/include/db0err.h
+++ b/storage/innobase/include/db0err.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2016, 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
@@ -137,6 +137,7 @@ enum dberr_t {
 					/*< Too many words in a phrase */
 
 	DB_TABLESPACE_TRUNCATED,	/*!< tablespace was truncated */
+
 	DB_DECRYPTION_FAILED,		/* Tablespace encrypted and
 					decrypt operation failed because
 					of missing key management plugin,
@@ -157,6 +158,12 @@ enum dberr_t {
 	DB_IO_NO_PUNCH_HOLE_TABLESPACE,	/*!< The tablespace doesn't support
 					punch hole */
 
+	DB_IO_DECRYPT_FAIL,		/*!< Failure to decrypt a page
+					after reading it from disk */
+
+	DB_IO_NO_ENCRYPT_TABLESPACE,	/*!< The tablespace doesn't support
+					encrypt */
+
 	DB_IO_PARTIAL_FAILED,		/*!< Partial IO request failed */
 
 	DB_FORCED_ABORT,		/*!< Transaction was forced to rollback
@@ -169,6 +176,10 @@ enum dberr_t {
 
 	DB_COMPUTE_VALUE_FAILED,	/*!< Compute generated value failed */
 
+	DB_NO_FK_ON_S_BASE_COL,		/*!< Cannot add foreign constrain
+					placed on the base column of
+					stored column */
+
 	/* 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 7915d69..f9ef39f 100644
--- a/storage/innobase/include/dict0crea.h
+++ b/storage/innobase/include/dict0crea.h
@@ -213,6 +213,20 @@ dict_create_add_foreigns_to_dictionary(
 	const dict_table_t*	table,
 	trx_t*			trx)
 	MY_ATTRIBUTE((nonnull, warn_unused_result));
+
+/** Check if a foreign constraint is on columns server as base columns
+of any stored column. This is to prevent creating SET NULL or CASCADE
+constraint on such columns
+ at param[in]	local_fk_set	set of foreign key objects, to be added to
+the dictionary tables
+ at param[in]	table		table to which the foreign key objects in
+local_fk_set belong to
+ at return true if yes, otherwise, false */
+bool
+dict_foreigns_has_s_base_col(
+	const dict_foreign_set&	local_fk_set,
+	const dict_table_t*	table);
+
 /****************************************************************//**
 Creates the tablespaces and datafiles system tables inside InnoDB
 at server bootstrap or server start if they are not found or are
diff --git a/storage/innobase/include/dict0defrag_bg.h b/storage/innobase/include/dict0defrag_bg.h
new file mode 100644
index 0000000..eb2a6e6
--- /dev/null
+++ b/storage/innobase/include/dict0defrag_bg.h
@@ -0,0 +1,93 @@
+/*****************************************************************************
+
+Copyright (c) 2016, 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
+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, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+ at file include/dict0defrag_bg.h
+Code used for background table and index
+defragmentation
+
+Created 25/08/2016 Jan Lindström
+*******************************************************/
+
+#ifndef dict0defrag_bg_h
+#define dict0defrag_bg_h
+
+#include "univ.i"
+
+#include "dict0types.h"
+#include "os0event.h"
+#include "os0thread.h"
+
+/*****************************************************************//**
+Initialize the defrag pool, called once during thread initialization. */
+void
+dict_defrag_pool_init(void);
+/*========================*/
+
+/*****************************************************************//**
+Free the resources occupied by the defrag pool, called once during
+thread de-initialization. */
+void
+dict_defrag_pool_deinit(void);
+/*==========================*/
+
+/*****************************************************************//**
+Add an index in a table to the defrag pool, which is processed by the
+background stats gathering thread. Only the table id and index id are
+added to the list, so the table can be closed after being enqueued and
+it will be opened when needed. If the table or index does not exist later
+(has been DROPped), then it will be removed from the pool and skipped. */
+void
+dict_stats_defrag_pool_add(
+/*=======================*/
+	const dict_index_t*	index);	/*!< in: table to add */
+
+/*****************************************************************//**
+Delete a given index from the auto defrag pool. */
+void
+dict_stats_defrag_pool_del(
+/*=======================*/
+	const dict_table_t*	table,	/*!<in: if given, remove
+					all entries for the table */
+	const dict_index_t*	index);	/*!< in: index to remove */
+
+/*****************************************************************//**
+Get the first index that has been added for updating persistent defrag
+stats and eventually save its stats. */
+void
+dict_defrag_process_entries_from_defrag_pool();
+/*===========================================*/
+
+/*********************************************************************//**
+Save defragmentation result.
+ at return DB_SUCCESS or error code */
+dberr_t
+dict_stats_save_defrag_summary(
+/*============================*/
+	dict_index_t*	index)	/*!< in: index */
+	MY_ATTRIBUTE((warn_unused_result));
+
+/*********************************************************************//**
+Save defragmentation stats for a given index.
+ at return DB_SUCCESS or error code */
+dberr_t
+dict_stats_save_defrag_stats(
+/*============================*/
+	dict_index_t*	index)	/*!< in: index */
+	MY_ATTRIBUTE((warn_unused_result));
+#endif /* dict0defrag_bg_h */
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index af7b91f..5022245 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -125,7 +125,7 @@ dict_table_open_on_id(
 	table_id_t	table_id,	/*!< in: table id */
 	ibool		dict_locked,	/*!< in: TRUE=data dictionary locked */
 	dict_table_op_t	table_op)	/*!< in: operation to perform */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /**********************************************************************//**
 Returns a table object based on table id.
@@ -309,7 +309,7 @@ ulint
 dict_col_get_index_pos(
 	const dict_col_t*	col,
 	const dict_index_t*	index)
-	__attribute__((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
 
 /****************************************************************//**
 If the given column name is reserved for InnoDB system columns, return
@@ -389,7 +389,7 @@ dict_table_add_system_columns(
 void
 dict_table_set_big_rows(
 	dict_table_t*	table)
-	__attribute__((nonnull));
+	MY_ATTRIBUTE((nonnull));
 /**********************************************************************//**
 Adds a table object to the dictionary cache. */
 void
@@ -531,7 +531,7 @@ dict_create_foreign_constraints(
 	size_t			sql_length,
 	const char*		name,
 	ibool			reject_fks)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**********************************************************************//**
 Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement.
 @return DB_SUCCESS or DB_CANNOT_DROP_CONSTRAINT if syntax error or the
@@ -565,7 +565,7 @@ dict_table_open_on_name(
 	ibool			dict_locked,
 	ibool			try_drop,
 	dict_err_ignore_t	ignore_err)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*********************************************************************//**
 Tries to find an index whose first fields are the columns in the array,
@@ -598,7 +598,7 @@ dict_foreign_find_index(
 					/*!< out: column number where
 					error happened */
 	dict_index_t**		err_index)
-			                /*!< out: index where error
+					/*!< out: index where error
 					happened */
 
 	MY_ATTRIBUTE((nonnull(1,3), warn_unused_result));
@@ -624,7 +624,7 @@ dict_table_get_col_name_for_mysql(
 	const dict_table_t*	table,	/*!< in: table */
 	const char*		col_name)/*!< in: MySQL table column name */
 	MY_ATTRIBUTE((nonnull, warn_unused_result));
-	
+
 /** Returns a virtual column's name.
 @param[in]	table		table object
 @param[in]	col_nr		virtual column number(nth virtual column)
@@ -634,7 +634,8 @@ dict_table_get_v_col_name(
 	const dict_table_t*	table,
 	ulint			col_nr);
 
-/**********************************************************************//**
+/** Check if the table has a given column.
+ at param[in]	table		table object
 @param[in]	col_name	column name
 @param[in]	col_nr		column number guessed, 0 as default
 @return column number if the table has the specified column,
@@ -656,6 +657,7 @@ dict_print_info_on_foreign_keys(
 				of SHOW TABLE STATUS */
 	trx_t*		trx,	/*!< in: transaction */
 	dict_table_t*	table);	/*!< in: table */
+
 /**********************************************************************//**
 Outputs info on a foreign key of a table in a format suitable for
 CREATE TABLE. */
@@ -665,6 +667,7 @@ dict_print_info_on_foreign_key_in_create_format(
 	trx_t*		trx,		/*!< in: transaction */
 	dict_foreign_t*	foreign,	/*!< in: foreign key constraint */
 	ibool		add_newline);	/*!< in: whether to add a newline */
+
 /*********************************************************************//**
 Tries to find an index whose first fields are the columns in the array,
 in the same order and is not marked for deletion and is not the same
@@ -756,7 +759,7 @@ ulint
 dict_index_is_clust(
 /*================*/
 	const dict_index_t*	index)	/*!< in: index */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Check if index is auto-generated clustered index.
 @param[in]	index	index
@@ -775,7 +778,7 @@ ulint
 dict_index_is_unique(
 /*=================*/
 	const dict_index_t*	index)	/*!< in: index */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /********************************************************************//**
 Check whether the index is a Spatial Index.
 @return	nonzero for Spatial Index, zero for other indexes */
@@ -784,7 +787,7 @@ ulint
 dict_index_is_spatial(
 /*==================*/
 	const dict_index_t*	index)	/*!< in: index */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /** Check whether the index contains a virtual column.
 @param[in]	index	index
 @return	nonzero for index on virtual column, zero for other indexes */
@@ -800,7 +803,7 @@ ulint
 dict_index_is_ibuf(
 /*===============*/
 	const dict_index_t*	index)	/*!< in: index */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /********************************************************************//**
 Check whether the index is a secondary index or the insert buffer tree.
 @return nonzero for insert buffer, zero for other indexes */
@@ -809,7 +812,7 @@ ulint
 dict_index_is_sec_or_ibuf(
 /*======================*/
 	const dict_index_t*	index)	/*!< in: index */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Get all the FTS indexes on a table.
 @param[in]	table	table
@@ -830,7 +833,7 @@ ulint
 dict_table_get_n_user_cols(
 /*=======================*/
 	const dict_table_t*	table)	/*!< in: table */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /** Gets the number of user-defined virtual and non-virtual columns in a table
 in the dictionary cache.
 @param[in]	table	table
@@ -849,7 +852,7 @@ ulint
 dict_table_get_n_sys_cols(
 /*======================*/
 	const dict_table_t*	table)	/*!< in: table */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /********************************************************************//**
 Gets the number of all non-virtual columns (also system) in a table
 in the dictionary cache.
@@ -859,7 +862,7 @@ ulint
 dict_table_get_n_cols(
 /*==================*/
 	const dict_table_t*	table)	/*!< in: table */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Gets the number of virtual columns in a table in the dictionary cache.
 @param[in]	table	the table to check
@@ -885,7 +888,7 @@ ib_uint64_t
 dict_table_get_n_rows(
 /*==================*/
 	const dict_table_t*	table)	/*!< in: table */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /********************************************************************//**
 Increment the number of rows in the table by one.
 Notice that this operation is not protected by any latch, the number is
@@ -1005,6 +1008,7 @@ dict_tf_get_format(
 /*===============*/
 	ulint		flags)		/*!< in: dict_table_t::flags */
 	MY_ATTRIBUTE((warn_unused_result));
+
 /** Set the various values in a dict_table_t::flags pointer.
 @param[in,out]	flags,		Pointer to a 4 byte Table Flags
 @param[in]	format,		File Format
@@ -1053,11 +1057,13 @@ fil_space_t::flags  |     0     |    0    |     1      |    1
 ==================================================================
 @param[in]	table_flags	dict_table_t::flags
 @param[in]	is_temp		whether the tablespace is temporary
+ at param[in]	is_encrypted	whether the tablespace is encrypted
 @return tablespace flags (fil_space_t::flags) */
 ulint
 dict_tf_to_fsp_flags(
 	ulint	table_flags,
-	bool	is_temp)
+	bool	is_temp,
+	bool	is_encrypted = false)
 	MY_ATTRIBUTE((const));
 
 /** Extract the page size from table flags.
@@ -1067,7 +1073,7 @@ UNIV_INLINE
 const page_size_t
 dict_tf_get_page_size(
 	ulint	flags)
-__attribute__((const));
+MY_ATTRIBUTE((const));
 
 /** Determine the extent size (in pages) for the given table
 @param[in]	table	the table whose extent size is being
@@ -1084,7 +1090,7 @@ UNIV_INLINE
 const page_size_t
 dict_table_page_size(
 	const dict_table_t*	table)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 #ifndef UNIV_HOTBACKUP
 /*********************************************************************//**
@@ -1194,7 +1200,7 @@ dict_index_add_to_cache(
 	dict_index_t*	index,
 	ulint		page_no,
 	ibool		strict)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Adds an index to the dictionary cache, with possible indexing newly
 added column.
@@ -1215,7 +1221,7 @@ dict_index_add_to_cache_w_vcol(
 	const dict_add_v_col_t* add_v,
 	ulint			page_no,
 	ibool			strict)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 #endif /* !UNIV_HOTBACKUP */
 /********************************************************************//**
 Gets the number of fields in the internal representation of an index,
@@ -1269,7 +1275,7 @@ UNIV_INLINE
 ulint
 dict_index_get_n_unique_in_tree_nonleaf(
 	const dict_index_t*	index)
-	__attribute__((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
 /********************************************************************//**
 Gets the number of user-defined ordering fields in the index. In the internal
 representation we add the row id to the ordering fields to make all indexes
@@ -1327,9 +1333,9 @@ dict_index_get_nth_col_pos(
 /*=======================*/
 	const dict_index_t*	index,	/*!< in: index */
 	ulint			n,	/*!< in: column number */
-	ulint*			prefix_col_pos) /*!< out: col num if prefix
-						*/
-	__attribute__((warn_unused_result));
+	ulint*			prefix_col_pos) /*!< out: col num if prefix */
+	MY_ATTRIBUTE((nonnull(1), warn_unused_result));
+
 /** Looks for column n in an index.
 @param[in]	index		index
 @param[in]	n		column number
@@ -1362,7 +1368,7 @@ dict_index_contains_col_or_prefix(
 	ulint			n,	/*!< in: column number */
 	bool			is_virtual)
 					/*!< in: whether it is a virtual col */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /********************************************************************//**
 Looks for a matching field in an index. The column has to be the same. The
 column in index must be complete, or must contain a prefix longer than the
@@ -1386,7 +1392,7 @@ dict_table_get_nth_col_pos(
 	const dict_table_t*	table,	/*!< in: table */
 	ulint			n,	/*!< in: column number */
 	ulint*			prefix_col_pos) /*!< out: col num if prefix */
-	__attribute__((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((nonnull(1), warn_unused_result));
 /********************************************************************//**
 Returns the position of a system column in an index.
 @return position, ULINT_UNDEFINED if not contained */
@@ -1668,6 +1674,7 @@ dict_tables_have_same_db(
 	const char*	name2)	/*!< in: table name in the form
 				dbname '/' tablename */
 	MY_ATTRIBUTE((nonnull, warn_unused_result));
+
 /** Get an index by name.
 @param[in]	table		the table where to look for the index
 @param[in]	name		the index name to look for
@@ -1679,19 +1686,13 @@ dict_table_get_index_on_name(
 	dict_table_t*	table,
 	const char*	name,
 	bool		committed=true)
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
+
 /** Get an index by name.
 @param[in]	table		the table where to look for the index
 @param[in]	name		the index name to look for
 @param[in]	committed	true=search for committed,
-false=search for uncommitted */
-dict_index_t*
-dict_table_find_index_on_id(
-/*========================*/
-	const dict_table_t*	table,	/*!< in: table instance */
-	index_id_t		id)	/*!< in: index id */
-	__attribute__((nonnull, warn_unused_result));
-/**********************************************************************//**
+false=search for uncommitted
 @return index, NULL if does not exist */
 inline
 const dict_index_t*
@@ -1715,7 +1716,7 @@ dict_table_is_fts_column(
 	ib_vector_t*	indexes,/* in: vector containing only FTS indexes */
 	ulint		col_no,	/* in: col number to search for */
 	bool		is_virtual)/*!< in: whether it is a virtual column */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**********************************************************************//**
 Prevent table eviction by moving a table to the non-LRU list from the
 LRU list if it is not already there. */
@@ -1724,7 +1725,8 @@ void
 dict_table_prevent_eviction(
 /*========================*/
 	dict_table_t*	table)	/*!< in: table to prevent eviction */
-	__attribute__((nonnull));
+	MY_ATTRIBUTE((nonnull));
+
 /**********************************************************************//**
 Move a table to the non LRU end of the LRU list. */
 void
@@ -1732,6 +1734,7 @@ dict_table_move_from_lru_to_non_lru(
 /*================================*/
 	dict_table_t*	table)	/*!< in: table to move from LRU to non-LRU */
 	MY_ATTRIBUTE((nonnull));
+
 /** Looks for an index with the given id given a table instance.
 @param[in]	table	table instance
 @param[in]	id	index id
@@ -1741,6 +1744,7 @@ dict_table_find_index_on_id(
 	const dict_table_t*	table,
 	index_id_t		id)
 	MY_ATTRIBUTE((nonnull(1)));
+
 /**********************************************************************//**
 Move to the most recently used segment of the LRU list. */
 void
@@ -1990,7 +1994,7 @@ bool
 dict_table_is_discarded(
 /*====================*/
 	const dict_table_t*	table)	/*!< in: table to check */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /********************************************************************//**
 Check if it is a temporary table.
@@ -2000,7 +2004,17 @@ bool
 dict_table_is_temporary(
 /*====================*/
 	const dict_table_t*	table)	/*!< in: table to check */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
+
+/********************************************************************//**
+Check if it is a encrypted table.
+ at return true if table encryption flag is set. */
+UNIV_INLINE
+bool
+dict_table_is_encrypted(
+/*====================*/
+	const dict_table_t*	table)	/*!< in: table to check */
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Check whether the table is intrinsic.
 An intrinsic table is a special kind of temporary table that
@@ -2018,7 +2032,16 @@ UNIV_INLINE
 bool
 dict_table_is_intrinsic(
 	const dict_table_t*	table)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
+
+/** Check if the table is in a shared tablespace (System or General).
+ at param[in]	id	Space ID to check
+ at return true if id is a shared tablespace, false if not. */
+UNIV_INLINE
+bool
+dict_table_in_shared_tablespace(
+	const dict_table_t*	table)
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Check whether locking is disabled for this table.
 Currently this is done for intrinsic table as their visibility is limited
@@ -2030,7 +2053,7 @@ UNIV_INLINE
 bool
 dict_table_is_locking_disabled(
 	const dict_table_t*	table)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /********************************************************************//**
 Turn-off redo-logging if temporary table. */
@@ -2105,7 +2128,7 @@ ulint
 dict_index_node_ptr_max_size(
 /*=========================*/
 	const dict_index_t*	index)	/*!< in: index */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /*****************************************************************//**
 Get index by first field of the index
 @return index which is having first field matches
@@ -2149,12 +2172,34 @@ dict_table_decode_n_col(
 	ulint*	n_v_col);
 
 /** Look for any dictionary objects that are found in the given tablespace.
- at param[in]	space	Tablespace ID to search for.
+ at param[in]	space_id	Tablespace ID to search for.
 @return true if tablespace is empty. */
 bool
-dict_tablespace_is_empty(
+dict_space_is_empty(
 	ulint	space_id);
 
+/** Find the space_id for the given name in sys_tablespaces.
+ at param[in]	name	Tablespace name to search for.
+ at return the tablespace ID. */
+ulint
+dict_space_get_id(
+	const char*	name);
+
+/** Free the virtual column template
+ at param[in,out]	vc_templ	virtual column template */
+UNIV_INLINE
+void
+dict_free_vc_templ(
+	dict_vcol_templ_t*	vc_templ);
+
+/** Check whether the table have virtual index.
+ at param[in]	table	InnoDB table
+ at return true if the table have virtual index, false otherwise. */
+UNIV_INLINE
+bool
+dict_table_have_virtual_index(
+	dict_table_t*	table);
+
 #endif /* !UNIV_HOTBACKUP */
 
 
diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic
index 9aa25b0..1a038d4 100644
--- a/storage/innobase/include/dict0dict.ic
+++ b/storage/innobase/include/dict0dict.ic
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2016, Oracle and/or its affiliates
+Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
 Copyright (c) 2013, 2016, MariaDB Corporation
 
 This program is free software; you can redistribute it and/or modify it under
@@ -338,6 +338,21 @@ dict_index_is_unique(
 }
 
 /********************************************************************//**
+Check whether the index is an universal index tree.
+ at return	nonzero for universal tree, zero for other indexes */
+UNIV_INLINE
+ulint
+dict_index_is_univ(
+/*===============*/
+	const dict_index_t*	index)	/*!< in: index */
+{
+	ut_ad(index);
+	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
+
+	return(index->type & DICT_UNIVERSAL);
+}
+
+/********************************************************************//**
 Check whether the index is a Spatial Index.
 @return	nonzero for Spatial Index, zero for other indexes */
 UNIV_INLINE
@@ -711,7 +726,7 @@ dict_tf_is_valid(
 		}
 	}
 
-        if (page_compression || page_compression_level) {
+	if (page_compression || page_compression_level) {
 		/* Page compression format must have compact and
 		atomic_blobs and page_compression_level requires
 		page_compression */
@@ -774,6 +789,7 @@ dict_tf2_is_valid(
 
 	bool	file_per_table = ((flags2 & DICT_TF2_USE_FILE_PER_TABLE) != 0);
 	bool	shared_space = DICT_TF_HAS_SHARED_SPACE(flags);
+
 	if (file_per_table && shared_space) {
 		return(false);
 	}
@@ -869,13 +885,13 @@ dict_sys_tables_type_validate(
 	format, so the DATA_DIR flag is compatible with any other
 	table flags. However, it is not used with TEMPORARY tables. */
 
-        if (page_compression || page_compression_level) {
+	if (page_compression || page_compression_level) {
 		/* page compressed row format must have low_order_bit and
 		atomic_blobs bits set and the DICT_N_COLS_COMPACT flag
 		should be in N_COLS, but we already know about the
 		low_order_bit and DICT_N_COLS_COMPACT flags. */
 
-                if (!atomic_blobs || !page_compression) {
+		if (!atomic_blobs || !page_compression) {
 			ib::error() << "SYS_TABLES::TYPE=" << type
 				<< " page_compression:" << page_compression
 				<< " page_compression_level:" << page_compression_level
@@ -1008,7 +1024,7 @@ dict_tf_set(
 
 	if (page_compressed) {
 		*flags |= (1 << DICT_TF_POS_ATOMIC_BLOBS)
-                       | (1 << DICT_TF_POS_PAGE_COMPRESSION)
+		       | (1 << DICT_TF_POS_PAGE_COMPRESSION)
 		       | (page_compression_level << DICT_TF_POS_PAGE_COMPRESSION_LEVEL);
 
 		ut_ad(zip_ssize == 0);
@@ -1067,7 +1083,7 @@ dict_tf_init(
 
 	if (page_compressed) {
 		flags |= (1 << DICT_TF_POS_ATOMIC_BLOBS)
-                      | (1 << DICT_TF_POS_PAGE_COMPRESSION)
+		      | (1 << DICT_TF_POS_PAGE_COMPRESSION)
 		      | (page_compression_level << DICT_TF_POS_PAGE_COMPRESSION_LEVEL);
 
 		ut_ad(zip_ssize == 0);
@@ -1706,9 +1722,11 @@ dict_max_v_field_len_store_undo(
 	for UNIV_FORMAT_B, upto col->max_prefix or
 	2) REC_VERSION_56_MAX_INDEX_COL_LEN, whichever is less */
 	if (dict_table_get_format(table) >= UNIV_FORMAT_B) {
-		max_log_len = (col->max_prefix > 0)
-			? col->max_prefix
-			: DICT_MAX_FIELD_LEN_BY_FORMAT(table);
+		if (DATA_BIG_COL(col) && col->max_prefix > 0) {
+			max_log_len = col->max_prefix;
+		} else {
+			max_log_len = DICT_MAX_FIELD_LEN_BY_FORMAT(table);
+		}
 	} else {
 		max_log_len = REC_ANTELOPE_MAX_INDEX_COL_LEN;
 	}
@@ -1786,6 +1804,18 @@ dict_table_is_temporary(
 	return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY));
 }
 
+/********************************************************************//**
+Check if it is a encrypted table.
+ at return true if table encrypted flag is set. */
+UNIV_INLINE
+bool
+dict_table_is_encrypted(
+/*====================*/
+	const dict_table_t*	table)	/*!< in: table to check */
+{
+	return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_ENCRYPTION));
+}
+
 /** Check whether the table is intrinsic.
 An intrinsic table is a special kind of temporary table that
 is invisible to the end user.  It can be created internally by InnoDB, the MySQL
@@ -1806,6 +1836,18 @@ dict_table_is_intrinsic(
 	return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_INTRINSIC));
 }
 
+/** Check if the table is in a shared tablespace (System or General).
+ at param[in]	id	Space ID to check
+ at return true if id is a shared tablespace, false if not. */
+UNIV_INLINE
+bool
+dict_table_in_shared_tablespace(
+	const dict_table_t*	table)
+{
+	return(is_system_tablespace(table->space)
+		|| DICT_TF_HAS_SHARED_SPACE(table->flags));
+}
+
 /** Check whether locking is disabled for this table.
 Currently this is done for intrinsic table as their visibility is limited
 to the connection only.
@@ -2003,4 +2045,45 @@ dict_table_decode_n_col(
 	*n_col = num & 0xFFFF;
 }
 
+/** Free the virtual column template
+ at param[in,out]	vc_templ	virtual column template */
+void
+dict_free_vc_templ(
+	dict_vcol_templ_t*	vc_templ)
+{
+	if (vc_templ->vtempl != NULL) {
+		ut_ad(vc_templ->n_v_col > 0);
+		for (ulint i = 0; i < vc_templ->n_col
+		     + vc_templ->n_v_col; i++) {
+			if (vc_templ->vtempl[i] != NULL) {
+				ut_free(vc_templ->vtempl[i]);
+			}
+		}
+		ut_free(vc_templ->default_rec);
+		ut_free(vc_templ->vtempl);
+		vc_templ->vtempl = NULL;
+	}
+}
+
+/** Check whether the table have virtual index.
+ at param[in]	table	InnoDB table
+ at return true if the table have virtual index, false otherwise. */
+UNIV_INLINE
+bool
+dict_table_have_virtual_index(
+	dict_table_t*	table)
+{
+	for (ulint col_no = 0; col_no < dict_table_get_n_v_cols(table);
+	     col_no++) {
+		const dict_v_col_t*	col
+			= dict_table_get_nth_v_col(table, col_no);
+
+		if (col->m_col.ord_part) {
+			return(true);
+		}
+	}
+
+	return(false);
+}
+
 #endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h
index 8e62022..6d01c38 100644
--- a/storage/innobase/include/dict0load.h
+++ b/storage/innobase/include/dict0load.h
@@ -184,6 +184,14 @@ dict_save_data_dir_path(
 	dict_table_t*	table,		/*!< in/out: table */
 	char*		filepath);	/*!< in: filepath of tablespace */
 
+/** Get the first filepath from SYS_DATAFILES for a given space_id.
+ at param[in]	space_id	Tablespace ID
+ at return First filepath (caller must invoke ut_free() on it)
+ at retval NULL if no SYS_DATAFILES entry was found. */
+char*
+dict_get_first_path(
+	ulint	space_id);
+
 /** Make sure the data_file_name is saved in dict_table_t if needed.
 Try to read it from the fil_system first, then from SYS_DATAFILES.
 @param[in]	table		Table object
@@ -262,7 +270,7 @@ dict_load_foreigns(
 						which must be loaded
 						subsequently to load all the
 						foreign key constraints. */
-	__attribute__((nonnull(1), warn_unused_result));
+	MY_ATTRIBUTE((nonnull(1), warn_unused_result));
 
 /********************************************************************//**
 This function opens a system table, and return the first record.
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 98ce7d3..4fac064 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -49,6 +49,8 @@ Created 1/8/1996 Heikki Tuuri
 #include "buf0buf.h"
 #include "gis0type.h"
 #include "os0once.h"
+#include "ut0new.h"
+
 #include "fil0fil.h"
 #include <my_crypt.h>
 #include "fil0crypt.h"
@@ -67,6 +69,8 @@ combination of types */
 				auto-generated clustered indexes,
 				also DICT_UNIQUE will be set */
 #define DICT_UNIQUE	2	/*!< unique index */
+#define	DICT_UNIVERSAL	4	/*!< index which can contain records from any
+				other index */
 #define	DICT_IBUF	8	/*!< insert buffer tree */
 #define	DICT_CORRUPT	16	/*!< bit to store the corrupted flag
 				in SYS_INDEXES.TYPE */
@@ -170,9 +174,9 @@ DEFAULT=0, ON = 1, OFF = 2
 			+ DICT_TF_WIDTH_SHARED_SPACE		\
 			+ DICT_TF_WIDTH_PAGE_COMPRESSION	\
 			+ DICT_TF_WIDTH_PAGE_COMPRESSION_LEVEL	\
-		        + DICT_TF_WIDTH_ATOMIC_WRITES		\
-		        + DICT_TF_WIDTH_PAGE_ENCRYPTION		\
-		        + DICT_TF_WIDTH_PAGE_ENCRYPTION_KEY)
+			+ DICT_TF_WIDTH_ATOMIC_WRITES		\
+			+ DICT_TF_WIDTH_PAGE_ENCRYPTION		\
+			+ DICT_TF_WIDTH_PAGE_ENCRYPTION_KEY)
 
 /** A mask of all the known/used bits in table flags */
 #define DICT_TF_BIT_MASK	(~(~0 << DICT_TF_BITS))
@@ -305,7 +309,7 @@ ROW_FORMAT=REDUNDANT.  InnoDB engines do not check these flags
 for unknown bits in order to protect backward incompatibility. */
 /* @{ */
 /** Total number of bits in table->flags2. */
-#define DICT_TF2_BITS			8
+#define DICT_TF2_BITS			9
 #define DICT_TF2_UNUSED_BIT_MASK	(~0U << DICT_TF2_BITS)
 #define DICT_TF2_BIT_MASK		~DICT_TF2_UNUSED_BIT_MASK
 
@@ -339,6 +343,9 @@ FTS, etc.... Intrinsic table has all the properties of the normal table except
 it is not created by user and so not visible to end-user. */
 #define DICT_TF2_INTRINSIC		128
 
+/** Encryption table bit. */
+#define DICT_TF2_ENCRYPTION		256
+
 /* @} */
 
 #define DICT_TF2_FLAG_SET(table, flag)		\
@@ -431,13 +438,22 @@ dict_mem_table_add_v_col(
 	ulint		len,
 	ulint		pos,
 	ulint		num_base);
+
+/** Adds a stored column definition to a table.
+ at param[in]	table		table
+ at param[in]	num_base	number of base columns. */
+void
+dict_mem_table_add_s_col(
+	dict_table_t*	table,
+	ulint		num_base);
+
 /**********************************************************************//**
 Renames a column of a table in the data dictionary cache. */
 void
 dict_mem_table_col_rename(
 /*======================*/
 	dict_table_t*	table,	/*!< in/out: table */
-	unsigned	nth_col,/*!< in: column index */
+	ulint		nth_col,/*!< in: column index */
 	const char*	from,	/*!< in: old column name */
 	const char*	to,	/*!< in: new column name */
 	bool		is_virtual);
@@ -532,6 +548,27 @@ dict_mem_referenced_table_name_lookup_set(
 	dict_foreign_t*	foreign,	/*!< in/out: foreign struct */
 	ibool		do_alloc);	/*!< in: is an alloc needed */
 
+/** Fills the dependent virtual columns in a set.
+Reason for being dependent are
+1) FK can be present on base column of virtual columns
+2) FK can be present on column which is a part of virtual index
+ at param[in,out] foreign foreign key information. */
+void
+dict_mem_foreign_fill_vcol_set(
+       dict_foreign_t*	foreign);
+
+/** Fill virtual columns set in each fk constraint present in the table.
+ at param[in,out] table   innodb table object. */
+void
+dict_mem_table_fill_foreign_vcol_set(
+        dict_table_t*	table);
+
+/** Free the vcol_set from all foreign key constraint on the table.
+ at param[in,out] table   innodb table object. */
+void
+dict_mem_table_free_foreign_vcol_set(
+	dict_table_t*	table);
+
 /** Create a temporary tablename like "#sql-ibtid-inc where
   tid = the Table ID
   inc = a randomly initialized number that is incremented for each file
@@ -696,6 +733,21 @@ struct dict_add_v_col_t{
 	const char**		v_col_name;
 };
 
+/** Data structure for a stored column in a table. */
+struct dict_s_col_t {
+	/** Stored column ptr */
+	dict_col_t*	m_col;
+	/** array of base col ptr */
+	dict_col_t**	base_col;
+	/** number of base columns */
+	ulint		num_base;
+	/** column pos in table */
+	ulint		s_pos;
+};
+
+/** list to put stored column for create_table_info_t */
+typedef std::list<dict_s_col_t, ut_allocator<dict_s_col_t> >	dict_s_col_list;
+
 /** @brief DICT_ANTELOPE_MAX_INDEX_COL_LEN is measured in bytes and
 is the maximum indexed column length (or indexed prefix length) in
 ROW_FORMAT=REDUNDANT and ROW_FORMAT=COMPACT. Also, in any format,
@@ -726,6 +778,7 @@ be REC_VERSION_56_MAX_INDEX_COL_LEN (3072) bytes */
 
 /** Defines the maximum fixed length column size */
 #define DICT_MAX_FIXED_COL_LEN		DICT_ANTELOPE_MAX_INDEX_COL_LEN
+
 #ifdef WITH_WSREP
 #define WSREP_MAX_SUPPORTED_KEY_LENGTH 3500
 #endif /* WITH_WSREP */
@@ -982,6 +1035,9 @@ struct dict_index_t{
 			parser;	/*!< fulltext parser plugin */
 	bool		is_ngram;
 				/*!< true if it's ngram parser */
+	bool		has_new_v_col;
+				/*!< whether it has a newly added virtual
+				column in ALTER */
 #ifndef UNIV_HOTBACKUP
 	UT_LIST_NODE_T(dict_index_t)
 			indexes;/*!< list of indexes of the table */
@@ -1106,6 +1162,11 @@ enum online_index_status {
 	ONLINE_INDEX_ABORTED_DROPPED
 };
 
+/** Set to store the virtual columns which are affected by Foreign
+key constraint. */
+typedef std::set<dict_v_col_t*, std::less<dict_v_col_t*>,
+		ut_allocator<dict_v_col_t*> >		dict_vcol_set;
+
 /** Data structure for a foreign key constraint; an example:
 FOREIGN KEY (A, B) REFERENCES TABLE2 (C, D).  Most fields will be
 initialized to 0, NULL or FALSE in dict_mem_foreign_create(). */
@@ -1141,6 +1202,9 @@ struct dict_foreign_t{
 					does not generate new indexes
 					implicitly */
 	dict_index_t*	referenced_index;/*!< referenced index */
+
+	dict_vcol_set*	v_cols;		/*!< set of virtual columns affected
+					by foreign key constraint. */
 };
 
 std::ostream&
@@ -1189,6 +1253,24 @@ struct dict_foreign_with_index {
 	const dict_index_t*	m_index;
 };
 
+#ifdef WITH_WSREP
+/** A function object to find a foreign key with the given index as the
+foreign index. Return the foreign key with matching criteria or NULL */
+struct dict_foreign_with_foreign_index {
+
+	dict_foreign_with_foreign_index(const dict_index_t*	index)
+	: m_index(index)
+	{}
+
+	bool operator()(const dict_foreign_t*	foreign) const
+	{
+		return(foreign->foreign_index == m_index);
+	}
+
+	const dict_index_t*	m_index;
+};
+#endif
+
 /* A function object to check if the foreign constraint is between different
 tables.  Returns true if foreign key constraint is between different tables,
 false otherwise. */
@@ -1273,6 +1355,10 @@ dict_foreign_free(
 /*==============*/
 	dict_foreign_t*	foreign)	/*!< in, own: foreign key struct */
 {
+	if (foreign->v_cols != NULL) {
+		UT_DELETE(foreign->v_cols);
+	}
+
 	mem_heap_free(foreign->heap);
 }
 
@@ -1332,12 +1418,42 @@ generate a specific template for it. */
 typedef ut_list_base<lock_t, ut_list_node<lock_t> lock_table_t::*>
 	table_lock_list_t;
 
+/** mysql template structure defined in row0mysql.cc */
+struct mysql_row_templ_t;
+
+/** Structure defines template related to virtual columns and
+their base columns */
+struct dict_vcol_templ_t {
+	/** number of regular columns */
+	ulint			n_col;
+
+	/** number of virtual columns */
+	ulint			n_v_col;
+
+	/** array of templates for virtual col and their base columns */
+	mysql_row_templ_t**	vtempl;
+
+	/** table's database name */
+	std::string		db_name;
+
+	/** table name */
+	std::string		tb_name;
+
+	/** share->table_name */
+	std::string		share_name;
+
+	/** MySQL record length */
+	ulint			rec_len;
+
+	/** default column value if any */
+	byte*			default_rec;
+};
+
 /* This flag is for sync SQL DDL and memcached DML.
 if table->memcached_sync_count == DICT_TABLE_IN_DDL means there's DDL running on
 the table, DML from memcached will be blocked. */
 #define DICT_TABLE_IN_DDL -1
 
-struct innodb_col_templ_t;
 /** These are used when MySQL FRM and InnoDB data dictionary are
 in inconsistent state. */
 typedef enum {
@@ -1363,6 +1479,7 @@ struct dict_table_t {
 
 	void*		thd;		/*!< thd */
 	fil_space_crypt_t *crypt_data; /*!< crypt data if present */
+
 	/** Release the table handle. */
 	inline void release();
 
@@ -1417,6 +1534,8 @@ struct dict_table_t {
 	5 whether the table is being created its own tablespace,
 	6 whether the table has been DISCARDed,
 	7 whether the aux FTS tables names are in hex.
+	8 whether the table is instinc table.
+	9 whether the table has encryption setting.
 	Use DICT_TF2_FLAG_IS_SET() to parse this flag. */
 	unsigned				flags2:DICT_TF2_BITS;
 
@@ -1470,6 +1589,13 @@ struct dict_table_t {
 	/** Array of virtual column descriptions. */
 	dict_v_col_t*				v_cols;
 
+	/** List of stored column descriptions. It is used only for foreign key
+	check during create table and copy alter operations.
+	During copy alter, s_cols list is filled during create table operation
+	and need to preserve till rename table operation. That is the
+	reason s_cols is a part of dict_table_t */
+	dict_s_col_list*			s_cols;
+
 	/** Column names packed in a character string
 	"name1\0name2\0...nameN\0". Until the string contains n_cols, it will
 	be allocated from a temporary heap. The final string will be allocated
@@ -1650,15 +1776,22 @@ struct dict_table_t {
 	/** The state of the background stats thread wrt this table.
 	See BG_STAT_NONE, BG_STAT_IN_PROGRESS and BG_STAT_SHOULD_QUIT.
 	Writes are covered by dict_sys->mutex. Dirty reads are possible. */
-#define BG_SCRUB_IN_PROGRESS	((byte)(1 << 2))
+
+	#define BG_SCRUB_IN_PROGRESS	((byte)(1 << 2))
 				/*!< BG_SCRUB_IN_PROGRESS is set in
 				stats_bg_flag when the background
 				scrub code is working on this table. The DROP
 				TABLE code waits for this to be cleared
 				before proceeding. */
 
-#define BG_IN_PROGRESS (BG_STAT_IN_PROGRESS | BG_SCRUB_IN_PROGRESS)
+	#define BG_STAT_SHOULD_QUIT		(1 << 1)
+
+	#define BG_IN_PROGRESS (BG_STAT_IN_PROGRESS | BG_SCRUB_IN_PROGRESS)
 
+
+	/** The state of the background stats thread wrt this table.
+	See BG_STAT_NONE, BG_STAT_IN_PROGRESS and BG_STAT_SHOULD_QUIT.
+	Writes are covered by dict_sys->mutex. Dirty reads are possible. */
 	byte					stats_bg_flag;
 
 	bool		stats_error_printed;
@@ -1752,8 +1885,10 @@ struct dict_table_t {
 	but just need a increased counter to track consistent view while
 	proceeding SELECT as part of UPDATE. */
 	ib_uint64_t				sess_trx_id;
+
 #endif /* !UNIV_HOTBACKUP */
-	ibool		is_encrypted;
+
+	bool					is_encrypted;
 
 #ifdef UNIV_DEBUG
 	/** Value of 'magic_n'. */
@@ -1764,10 +1899,13 @@ struct dict_table_t {
 #endif /* UNIV_DEBUG */
 	/** mysql_row_templ_t for base columns used for compute the virtual
 	columns */
-	innodb_col_templ_t*			vc_templ;
+	dict_vcol_templ_t*			vc_templ;
 
-	/** whether above vc_templ comes from purge allocation */
-	bool					vc_templ_purge;
+	/** encryption key, it's only for export/import */
+	byte*					encryption_key;
+
+	/** encryption iv, it's only for export/import */
+	byte*					encryption_iv;
 };
 
 /*******************************************************************//**
@@ -1871,29 +2009,20 @@ dict_table_autoinc_own(
 }
 #endif /* UNIV_DEBUG */
 
-/** whether a col is used in spatial index or regular index */
-enum col_spatial_status {
-	/** Not used in gis index. */
-	SPATIAL_NONE	= 0,
-
-	/** Used in both spatial index and regular index. */
-	SPATIAL_MIXED	= 1,
-
-	/** Only used in spatial index. */
-	SPATIAL_ONLY	= 2
-};
-
 /** Check whether the col is used in spatial index or regular index.
 @param[in]	col	column to check
- at return col_spatial_status */
+ at return spatial status */
 inline
-col_spatial_status
+spatial_status_t
 dict_col_get_spatial_status(
 	const dict_col_t*	col)
 {
-	col_spatial_status	spatial_status = SPATIAL_NONE;
+	spatial_status_t	spatial_status = SPATIAL_NONE;
 
-	ut_ad(col->ord_part);
+	/* Column is not a part of any index. */
+	if (!col->ord_part) {
+		return(spatial_status);
+	}
 
 	if (DATA_GEOMETRY_MTYPE(col->mtype)) {
 		if (col->max_prefix == 0) {
diff --git a/storage/innobase/include/dict0stats.h b/storage/innobase/include/dict0stats.h
index 40f254b..8941b39 100644
--- a/storage/innobase/include/dict0stats.h
+++ b/storage/innobase/include/dict0stats.h
@@ -233,6 +233,42 @@ dict_stats_empty_defrag_stats(
 	dict_index_t* index);	/*!< in: index to clear defragmentation stats */
 
 
+/*********************************************************************//**
+Renames an index in InnoDB persistent stats storage.
+This function creates its own transaction and commits it.
+ at return DB_SUCCESS or error code. DB_STATS_DO_NOT_EXIST will be returned
+if the persistent stats do not exist. */
+dberr_t
+dict_stats_rename_index(
+/*====================*/
+	const dict_table_t*	table,		/*!< in: table whose index
+						is renamed */
+	const char*		old_index_name,	/*!< in: old index name */
+	const char*		new_index_name)	/*!< in: new index name */
+	MY_ATTRIBUTE((warn_unused_result));
+
+/** Save an individual index's statistic into the persistent statistics
+storage.
+ at param[in]	index			index to be updated
+ at param[in]	last_update		timestamp of the stat
+ at param[in]	stat_name		name of the stat
+ at param[in]	stat_value		value of the stat
+ at param[in]	sample_size		n pages sampled or NULL
+ at param[in]	stat_description	description of the stat
+ at param[in,out]	trx			in case of NULL the function will
+allocate and free the trx object. If it is not NULL then it will be
+rolled back only in the case of error, but not freed.
+ at return DB_SUCCESS or error code */
+dberr_t
+dict_stats_save_index_stat(
+	dict_index_t*	index,
+	lint		last_update,
+	const char*	stat_name,
+	ib_uint64_t	stat_value,
+	ib_uint64_t*	sample_size,
+	const char*	stat_description,
+	trx_t*		trx);
+
 #ifndef UNIV_NONINL
 #include "dict0stats.ic"
 #endif
diff --git a/storage/innobase/include/dict0stats_bg.h b/storage/innobase/include/dict0stats_bg.h
index e04d9ab5a..50c2591 100644
--- a/storage/innobase/include/dict0stats_bg.h
+++ b/storage/innobase/include/dict0stats_bg.h
@@ -39,6 +39,11 @@ extern os_event_t	dict_stats_event;
 extern mysql_pfs_key_t	dict_stats_recalc_pool_mutex_key;
 #endif /* HAVE_PSI_INTERFACE */
 
+#ifdef UNIV_DEBUG
+/** Value of MySQL global used to disable dict_stats thread. */
+extern my_bool		innodb_dict_stats_disabled_debug;
+#endif /* UNIV_DEBUG */
+
 /*****************************************************************//**
 Add a table to the recalc pool, which is processed by the
 background stats gathering thread. Only the table id is added to the
@@ -58,28 +63,6 @@ dict_stats_recalc_pool_del(
 /*=======================*/
 	const dict_table_t*	table);	/*!< in: table to remove */
 
-/*****************************************************************//**
-Add an index in a table to the defrag pool, which is processed by the
-background stats gathering thread. Only the table id and index id are
-added to the list, so the table can be closed after being enqueued and
-it will be opened when needed. If the table or index does not exist later
-(has been DROPped), then it will be removed from the pool and skipped. */
-UNIV_INTERN
-void
-dict_stats_defrag_pool_add(
-/*=======================*/
-	const dict_index_t*	index);	/*!< in: table to add */
-
-/*****************************************************************//**
-Delete a given index from the auto defrag pool. */
-UNIV_INTERN
-void
-dict_stats_defrag_pool_del(
-/*=======================*/
-	const dict_table_t*	table,	/*!<in: if given, remove
-					all entries for the table */
-	const dict_index_t*	index);	/*!< in: index to remove */
-
 /** Yield the data dictionary latch when waiting
 for the background thread to stop accessing a table.
 @param trx transaction holding the data dictionary locks */
@@ -129,6 +112,21 @@ void
 dict_stats_thread_deinit();
 /*======================*/
 
+#ifdef UNIV_DEBUG
+/** Disables dict stats thread. It's used by:
+	SET GLOBAL innodb_dict_stats_disabled_debug = 1 (0).
+ at param[in]	thd		thread handle
+ at param[in]	var		pointer to system variable
+ at param[out]	var_ptr		where the formal string goes
+ at param[in]	save		immediate result from check function */
+void
+dict_stats_disabled_debug_update(
+	THD*				thd,
+	struct st_mysql_sys_var*	var,
+	void*				var_ptr,
+	const void*			save);
+#endif /* UNIV_DEBUG */
+
 /*****************************************************************//**
 This is the thread for background stats gathering. It pops tables, from
 the auto recalc list and proceeds them, eventually recalculating their
@@ -141,6 +139,10 @@ DECLARE_THREAD(dict_stats_thread)(
 	void*	arg);	/*!< in: a dummy parameter
 			required by os_thread_create */
 
+/** Shutdown the dict stats thread. */
+void
+dict_stats_shutdown();
+
 # ifndef UNIV_NONINL
 #  include "dict0stats_bg.ic"
 # endif
diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h
index 5e6e562..ae002dd 100644
--- a/storage/innobase/include/dict0types.h
+++ b/storage/innobase/include/dict0types.h
@@ -1,7 +1,7 @@
 /*****************************************************************************
 
 Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
+Copyright (c) 2013, 2016, 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
@@ -104,4 +104,31 @@ typedef ib_mutex_t DictSysMutex;
 extern uint		ibuf_debug;
 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
 
+/** Shift for spatial status */
+#define SPATIAL_STATUS_SHIFT	12
+
+/** Mask to encode/decode spatial status. */
+#define SPATIAL_STATUS_MASK	(3 << SPATIAL_STATUS_SHIFT)
+
+#if SPATIAL_STATUS_MASK < REC_VERSION_56_MAX_INDEX_COL_LEN
+# error SPATIAL_STATUS_MASK < REC_VERSION_56_MAX_INDEX_COL_LEN
+#endif
+
+/** whether a col is used in spatial index or regular index
+Note: the spatial status is part of persistent undo log,
+so we should not modify the values in MySQL 5.7 */
+enum spatial_status_t {
+	/* Unkown status (undo format in 5.7.9) */
+	SPATIAL_UNKNOWN = 0,
+
+	/** Not used in gis index. */
+	SPATIAL_NONE	= 1,
+
+	/** Used in both spatial index and regular index. */
+	SPATIAL_MIXED	= 2,
+
+	/** Only used in spatial index. */
+	SPATIAL_ONLY	= 3
+};
+
 #endif
diff --git a/storage/innobase/include/dyn0buf.h b/storage/innobase/include/dyn0buf.h
index 7e2995c..3126c8e 100644
--- a/storage/innobase/include/dyn0buf.h
+++ b/storage/innobase/include/dyn0buf.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2013, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, 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
@@ -62,7 +62,7 @@ class dyn_buf_t {
 		Gets the number of used bytes in a block.
 		@return	number of bytes used */
 		ulint used() const
-			__attribute__((warn_unused_result))
+			MY_ATTRIBUTE((warn_unused_result))
 		{
 			return(static_cast<ulint>(m_used & ~DYN_BLOCK_FULL_FLAG));
 		}
@@ -71,7 +71,7 @@ class dyn_buf_t {
 		Gets pointer to the start of data.
 		@return	pointer to data */
 		byte* start()
-			__attribute__((warn_unused_result))
+			MY_ATTRIBUTE((warn_unused_result))
 		{
 			return(m_data);
 		}
@@ -79,7 +79,7 @@ class dyn_buf_t {
 		/**
 		@return start of data - non const version */
 		byte* begin()
-			__attribute__((warn_unused_result))
+			MY_ATTRIBUTE((warn_unused_result))
 		{
 			return(m_data);
 		}
@@ -87,7 +87,7 @@ class dyn_buf_t {
 		/**
 		@return end of used data - non const version */
 		byte* end()
-			__attribute__((warn_unused_result))
+			MY_ATTRIBUTE((warn_unused_result))
 		{
 			return(begin() + m_used);
 		}
@@ -95,7 +95,7 @@ class dyn_buf_t {
 		/**
 		@return start of data - const version */
 		const byte* begin() const
-			__attribute__((warn_unused_result))
+			MY_ATTRIBUTE((warn_unused_result))
 		{
 			return(m_data);
 		}
@@ -103,7 +103,7 @@ class dyn_buf_t {
 		/**
 		@return end of used data - const version */
 		const byte* end() const
-			__attribute__((warn_unused_result))
+			MY_ATTRIBUTE((warn_unused_result))
 		{
 			return(begin() + m_used);
 		}
@@ -216,7 +216,7 @@ class dyn_buf_t {
 	@param size	in bytes of the buffer; MUST be <= MAX_DATA_SIZE!
 	@return	pointer to the buffer */
 	byte* open(ulint size)
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		ut_ad(size > 0);
 		ut_ad(size <= MAX_DATA_SIZE);
@@ -319,7 +319,7 @@ class dyn_buf_t {
 	Returns the size of the total stored data.
 	@return	data size in bytes */
 	ulint size() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 #ifdef UNIV_DEBUG
 		ulint	total_size = 0;
@@ -375,7 +375,7 @@ class dyn_buf_t {
 	/**
 	@return the first block */
 	block_t* front()
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		ut_ad(UT_LIST_GET_LEN(m_list) > 0);
 		return(UT_LIST_GET_FIRST(m_list));
@@ -384,7 +384,7 @@ class dyn_buf_t {
 	/**
 	@return true if m_first_block block was not filled fully */
 	bool is_small() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return(m_heap == NULL);
 	}
diff --git a/storage/innobase/include/fil0crypt.ic b/storage/innobase/include/fil0crypt.ic
index 1a91aee..65ca4de 100644
--- a/storage/innobase/include/fil0crypt.ic
+++ b/storage/innobase/include/fil0crypt.ic
@@ -17,7 +17,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
 *****************************************************************************/
 
 /**************************************************//**
- at file include/fil0fil.h
+ at file include/fil0crypt.ic
 The low-level file system encryption support functions
 
 Created 04/01/2015 Jan Lindström
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index d04355c..4171bed 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2016, Oracle and/or its affiliates.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
 Copyright (c) 2013, 2016, MariaDB Corporation.
 
 This program is free software; you can redistribute it and/or modify it under
@@ -33,7 +33,6 @@ Created 10/25/1995 Heikki Tuuri
 #include "log0recv.h"
 #include "dict0types.h"
 #include "page0size.h"
-#include "hash0hash.h"
 #ifndef UNIV_HOTBACKUP
 #include "ibuf0types.h"
 #else
@@ -45,6 +44,53 @@ Created 10/25/1995 Heikki Tuuri
 #include <list>
 #include <vector>
 
+#ifdef UNIV_HOTBACKUP
+#include <cstring>
+/** determine if file is intermediate / temporary.These files are created during
+reorganize partition, rename tables, add / drop columns etc.
+ at param[in]	filepath asbosolute / relative or simply file name
+ at retvalue	true	if it is intermediate file
+ at retvalue	false	if it is normal file */
+inline
+bool
+is_intermediate_file(const std::string& filepath)
+{
+	std::string file_name = filepath;
+
+	// extract file name from relative or absolute file name
+	std::size_t pos = file_name.rfind(OS_PATH_SEPARATOR);
+	if (pos != std::string::npos)
+		file_name = file_name.substr(++pos);
+
+	transform(file_name.begin(), file_name.end(),
+		file_name.begin(), ::tolower);
+
+	if (file_name[0] != '#') {
+		pos = file_name.rfind("#tmp#.ibd");
+		if (pos != std::string::npos)
+			return true;
+		else
+			return false;  /* normal file name */
+	}
+
+	std::vector<std::string> file_name_patterns = {"#sql-", "#sql2-",
+		"#tmp#", "#ren#"};
+
+	/* search for the unsupported patterns */
+	for (auto itr = file_name_patterns.begin();
+		itr != file_name_patterns.end();
+		itr++) {
+
+		if (0 == std::strncmp(file_name.c_str(),
+			itr->c_str(), itr->length())){
+			return true;
+		}
+	}
+
+	return false;
+}
+#endif /* UNIV_HOTBACKUP */
+
 extern const char general_space_name[];
 
 // Forward declaration
@@ -54,6 +100,7 @@ class truncate_t;
 struct fil_node_t;
 struct fil_space_t;
 struct btr_create_t;
+
 /* structure containing encryption specification */
 typedef struct fil_space_crypt_struct fil_space_crypt_t;
 
@@ -92,12 +139,6 @@ struct fil_node_t;
 struct fil_space_t {
 	char*		name;	/*!< Tablespace name */
 	ulint		id;	/*!< space id */
-	ib_uint64_t	tablespace_version;
-				/*!< in DISCARD/IMPORT this timestamp
-				is used to check if we should ignore
-				an insert buffer merge request for a
-				page because it actually was for the
-				previous incarnation of the space */
 	lsn_t		max_lsn;
 				/*!< LSN of the most recent
 				fil_names_write_if_was_clean().
@@ -181,17 +222,29 @@ struct fil_space_t {
 	/** Compression algorithm */
 	Compression::Type	compression_type;
 
+	/** Encryption algorithm */
+	Encryption::Type	encryption_type;
+
+	/** Encrypt key */
+	byte			encryption_key[ENCRYPTION_KEY_LEN];
+
+	/** Encrypt key length*/
+	ulint			encryption_klen;
+
+	/** Encrypt initial vector */
+	byte			encryption_iv[ENCRYPTION_KEY_LEN];
+
+	/** MariaDB encryption data */
+        fil_space_crypt_t* crypt_data;
+
+	/** Space file block size */
+	ulint		file_block_size;
+
+	/** True if we have already printed compression failure */
 	bool		printed_compression_failure;
-				/*!< true if we have already printed
-				compression failure */
-	fil_space_crypt_t* crypt_data;
-				/* Tablespace crypt information or
-				NULL */
-	bool		read_page0;
-				/*!< true if page 0 of this tablespace
-				is read */
 
-	ulint		file_block_size;/*!< file system block size */
+	/** True if page 0 of tablespace is read */
+	bool		read_page0;
 
 	/** Release the reserved free extents.
 	@param[in]	n_reserved	number of reserved extents */
@@ -205,54 +258,53 @@ struct fil_space_t {
 
 /** File node of a tablespace or the log data space */
 struct fil_node_t {
-	fil_space_t*	space;	/*!< backpointer to the space where this node
-				belongs */
-	char*		name;	/*!< path to the file */
-	bool		is_open;/*!< true if file is open */
-	os_file_t	handle;	/*!< OS handle to the file, if file open */
-	os_event_t	sync_event;/*!< Condition event to group and
-				serialize calls to fsync */
-	bool		is_raw_disk;/*!< true if the 'file' is actually a raw
-				device or a raw disk partition */
-	ulint		size;	/*!< size of the file in database pages, 0 if
-				not known yet; the possible last incomplete
-				megabyte may be ignored if space == 0 */
+	/** tablespace containing this file */
+	fil_space_t*	space;
+	/** file name; protected by fil_system->mutex and log_sys->mutex. */
+	char*		name;
+	/** whether this file is open */
+	bool		is_open;
+	/** file handle (valid if is_open) */
+	os_file_t	handle;
+	/** event that groups and serializes calls to fsync */
+	os_event_t	sync_event;
+	/** whether the file actually is a raw device or disk partition */
+	bool		is_raw_disk;
+	/** size of the file in database pages (0 if not known yet);
+	the possible last incomplete megabyte may be ignored
+	if space->id == 0 */
+	ulint		size;
+	/** initial size of the file in database pages;
+	FIL_IBD_FILE_INITIAL_SIZE by default */
 	ulint		init_size;
-				/*!< initial size of the file in database pages,
-				defaults to FIL_IBD_FILE_INITIAL_SIZE. */
+	/** maximum size of the file in database pages (0 if unlimited) */
 	ulint		max_size;
-				/*!< maximum size of the file in database pages;
-				0 if there is no maximum size. */
+	/** count of pending i/o's; is_open must be true if nonzero */
 	ulint		n_pending;
-				/*!< count of pending i/o's on this file;
-				closing of the file is not allowed if
-				this is > 0 */
+	/** count of pending flushes; is_open must be true if nonzero */
 	ulint		n_pending_flushes;
-				/*!< count of pending flushes on this file;
-				closing of the file is not allowed if
-				this is > 0 */
+	/** whether the file is currently being extended */
 	bool		being_extended;
-				/*!< true if the node is currently
-				being extended. */
-	int64_t		modification_counter;/*!< when we write to the file we
-				increment this by one */
-	int64_t		flush_counter;/*!< up to what
-				modification_counter value we have
-				flushed the modifications to disk */
+	/** number of writes to the file since the system was started */
+	int64_t		modification_counter;
+	/** the modification_counter of the latest flush to disk */
+	int64_t		flush_counter;
+	/** link to other files in this tablespace */
 	UT_LIST_NODE_T(fil_node_t) chain;
-				/*!< link field for the file chain */
+	/** link to the fil_system->LRU list (keeping track of open files) */
 	UT_LIST_NODE_T(fil_node_t) LRU;
-				/*!< link field for the LRU list */
-	ulint		magic_n;/*!< FIL_NODE_MAGIC_N */
 
-	/** true if the FS where the file is located supports PUNCH HOLE */
+	/** whether the file system of this file supports PUNCH HOLE */
 	bool		punch_hole;
 
-	/** Block size to use for punching holes */
-	ulint           block_size;
+	/** block size to use for punching holes */
+	ulint		block_size;
 
-	/** True if atomic write is enabled for this file */
+	/** whether atomic write is enabled for this file */
 	bool		atomic_write;
+
+	/** FIL_NODE_MAGIC_N */
+	ulint		magic_n;
 };
 
 /** Value of fil_node_t::magic_n */
@@ -263,12 +315,14 @@ enum ib_extention {
 	NO_EXT = 0,
 	IBD = 1,
 	ISL = 2,
-	CFG = 3
+	CFG = 3,
+	CFP = 4
 };
 extern const char* dot_ext[];
 #define DOT_IBD dot_ext[IBD]
 #define DOT_ISL dot_ext[ISL]
 #define DOT_CFG dot_ext[CFG]
+#define DOT_CPF dot_ext[CFP]
 
 /** Wrapper for a path to a directory.
 This folder may or may not yet esist.  Since not all directory paths
@@ -473,6 +527,7 @@ static const ulint FIL_PAGE_COMPRESS_SIZE_V1 = FIL_PAGE_ORIGINAL_SIZE_V1 + 2;
 #define FIL_PAGE_SPACE_ID  FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID
 
 #define FIL_PAGE_DATA		38U	/*!< start of the data on the page */
+
 /* Following are used when page compression is used */
 #define FIL_PAGE_COMPRESSED_SIZE 2      /*!< Number of bytes used to store
 					actual payload data size on
@@ -512,6 +567,10 @@ static const ulint FIL_PAGE_COMPRESS_SIZE_V1 = FIL_PAGE_ORIGINAL_SIZE_V1 + 2;
 					in FIL_PAGE_TYPE is replaced with this
 					value when flushing pages. */
 #define FIL_PAGE_COMPRESSED	14	/*!< Compressed page */
+#define FIL_PAGE_ENCRYPTED	15	/*!< Encrypted page */
+#define FIL_PAGE_COMPRESSED_AND_ENCRYPTED 16
+					/*!< Compressed and Encrypted page */
+#define FIL_PAGE_ENCRYPTED_RTREE 17	/*!< Encrypted R-tree page */
 
 /** Used by i_s.cc to index into the text description. */
 #define FIL_PAGE_TYPE_LAST	FIL_PAGE_TYPE_UNKNOWN
@@ -540,6 +599,20 @@ extern ulint	fil_n_pending_tablespace_flushes;
 /** Number of files currently open */
 extern ulint	fil_n_file_opened;
 
+/** Look up a tablespace.
+The caller should hold an InnoDB table lock or a MDL that prevents
+the tablespace from being dropped during the operation,
+or the caller should be in single-threaded crash recovery mode
+(no user connections that could drop tablespaces).
+If this is not the case, fil_space_acquire() and fil_space_release()
+should be used instead.
+ at param[in]	id	tablespace ID
+ at return tablespace, or NULL if not found */
+fil_space_t*
+fil_space_get(
+	ulint	id)
+	MY_ATTRIBUTE((warn_unused_result));
+
 /** The tablespace memory cache; also the totality of logs (the log
 data space) is stored here; below we talk about tablespaces, but also
 the ib_logfiles form a 'space' and it is handled here */
@@ -602,30 +675,13 @@ struct fil_system_t {
 					potential space_id reuse */
 };
 
-#ifndef UNIV_HOTBACKUP
-/** Look up a tablespace.
-The caller should hold an InnoDB table lock or a MDL that prevents
-the tablespace from being dropped during the operation,
-or the caller should be in single-threaded crash recovery mode
-(no user connections that could drop tablespaces).
-If this is not the case, fil_space_acquire() and fil_space_release()
-should be used instead.
- at param[in]	id	tablespace ID
- at return tablespace, or NULL if not found */
-fil_space_t*
-fil_space_get(
-	ulint	id)
-	__attribute__((warn_unused_result));
+/** The tablespace memory cache. This variable is NULL before the module is
+initialized. */
+extern fil_system_t*	fil_system;
 
-/*******************************************************************//**
-Returns the version number of a tablespace, -1 if not found.
- at return version number, -1 if the tablespace does not exist in the
-memory cache */
-UNIV_INTERN
-ib_uint64_t
-fil_space_get_version(
-/*==================*/
-	ulint	id);	/*!< in: space id */
+#include "fil0crypt.h"
+
+#ifndef UNIV_HOTBACKUP
 /** Returns the latch of a file space.
 @param[in]	id	space id
 @param[out]	flags	tablespace flags
@@ -658,7 +714,7 @@ fil_space_set_imported(
 @return whether it is a temporary tablespace */
 bool
 fsp_is_temporary(ulint id)
-__attribute__((warn_unused_result, pure));
+MY_ATTRIBUTE((warn_unused_result, pure));
 # endif /* UNIV_DEBUG */
 #endif /* !UNIV_HOTBACKUP */
 
@@ -680,7 +736,7 @@ fil_node_create(
 	bool		is_raw,
 	bool		atomic_write,
 	ulint		max_pages = ULINT_MAX)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Create a space memory object and put it to the fil_system hash table.
 The tablespace name is independent from the tablespace file-name.
@@ -693,12 +749,12 @@ Error messages are issued to the server log.
 @retval NULL on failure (such as when the same tablespace exists) */
 fil_space_t*
 fil_space_create(
-	const char*	name,		/*!< in: space name */
-	ulint		id,		/*!< in: space id */
+	const char*	name,
+	ulint		id,
 	ulint		flags,
 	fil_type_t	purpose,	/*!< in: FIL_TABLESPACE, or FIL_LOG if log */
 	fil_space_crypt_t* crypt_data)	/*!< in: crypt data */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*******************************************************************//**
 Assigns a new space id for a new single-table tablespace. This works simply by
@@ -820,22 +876,15 @@ fil_set_max_space_id_if_bigger(
 /*===========================*/
 	ulint	max_id);/*!< in: maximum known id */
 #ifndef UNIV_HOTBACKUP
-/*******************************************************************//**
-Increments the count of pending operation, if space is not being deleted.
- at return	TRUE if being deleted, and operation should be skipped */
-UNIV_INTERN
-ibool
-fil_inc_pending_ops(
-/*================*/
-	ulint	id,		/*!< in: space id */
-	ibool	print_err);	/*!< in: need to print error or not */
-/*******************************************************************//**
-Decrements the count of pending operations. */
-UNIV_INTERN
-void
-fil_decr_pending_ops(
-/*=================*/
-	ulint	id);	/*!< in: space id */
+
+/** Write the flushed LSN to the page header of the first page in the
+system tablespace.
+ at param[in]	lsn	flushed LSN
+ at return DB_SUCCESS or error number */
+dberr_t
+fil_write_flushed_lsn(
+	lsn_t	lsn)
+MY_ATTRIBUTE((warn_unused_result));
 
 /** Acquire a tablespace when it could be dropped concurrently.
 Used by background threads that do not necessarily hold proper locks
@@ -845,7 +894,7 @@ for concurrency control.
 fil_space_t*
 fil_space_acquire(
 	ulint	id)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Acquire a tablespace that may not exist.
 Used by background threads that do not necessarily hold proper locks
@@ -855,7 +904,7 @@ for concurrency control.
 fil_space_t*
 fil_space_acquire_silent(
 	ulint	id)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Release a tablespace acquired with fil_space_acquire().
 @param[in,out]	space	tablespace to release  */
@@ -919,6 +968,7 @@ class FilSpace
 };
 
 #endif /* !UNIV_HOTBACKUP */
+
 /********************************************************//**
 Creates the database directory for a table if it does not exist yet. */
 void
@@ -968,7 +1018,7 @@ fil_op_replay_rename(
 	ulint		first_page_no,
 	const char*	name,
 	const char*	new_name)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Deletes an IBD tablespace, either general or single-table.
 The tablespace must be cached in the memory cache. This will delete the
@@ -1084,8 +1134,6 @@ fil_make_filepath(
 	ib_extention	suffix,
 	bool		strip_name);
 
-#include "fil0crypt.h"
-
 /** Creates a new General or Single-Table tablespace
 @param[in]	space_id	Tablespace ID
 @param[in]	name		Tablespace name in dbname/tablename format.
@@ -1104,9 +1152,8 @@ fil_ibd_create(
 	ulint		size,
 	fil_encryption_t mode,	/*!< in: encryption mode */
 	ulint		key_id) /*!< in: encryption key_id */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
-#ifndef UNIV_HOTBACKUP
 /********************************************************************//**
 Tries to open a single-table tablespace and optionally checks the space id is
 right in it. If does not succeed, prints an error message to the .err log. This
@@ -1146,7 +1193,7 @@ fil_ibd_open(
 	const char*	tablename,
 	const char*	path_in,
 	dict_table_t*	table)	/*!< in: table */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 enum fil_load_status {
 	/** The tablespace file(s) were found and valid. */
@@ -1169,9 +1216,8 @@ fil_ibd_load(
 	ulint		space_id,
 	const char*	filename,
 	fil_space_t*&	space)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
-#endif /* !UNIV_HOTBACKUP */
 
 /***********************************************************************//**
 A fault-tolerant function that tries to read the next file name in the
@@ -1268,6 +1314,11 @@ fil_space_get_n_reserved_extents(
 				aligned
 @param[in]	message		message for aio handler if non-sync aio
 				used, else ignored
+ at param[in,out]	write_size	Actual write size initialized
+				after fist successfull trim
+				operation for this page and if
+				nitialized we do not trim again if
+				Actual page
 
 @return DB_SUCCESS, DB_TABLESPACE_DELETED or DB_TABLESPACE_TRUNCATED
 if we are trying to do i/o on a tablespace which does not exist */
@@ -1281,11 +1332,7 @@ fil_io(
 	ulint			len,
 	void*			buf,
 	void*			message,
-	ulint*	write_size);	/*!< in/out: Actual write size initialized
-			       after fist successfull trim
-			       operation for this page and if
-			       initialized we do not trim again if
-			       actual page size does not decrease. */
+	ulint*			write_size);
 /**********************************************************************//**
 Waits for an aio operation to complete. This function is used to write the
 handler for completed requests. The aio array of pending requests is divided
@@ -1477,6 +1524,10 @@ struct PageCallback {
 	@return the space id of the tablespace */
 	virtual ulint get_space_id() const UNIV_NOTHROW = 0;
 
+	/**
+	@retval the space flags of the tablespace being iterated over */
+	virtual ulint get_space_flags() const UNIV_NOTHROW = 0;
+
 	/** Set the tablespace table size.
 	@param[in] page a page belonging to the tablespace */
 	void set_page_size(const buf_frame_t* page) UNIV_NOTHROW;
@@ -1515,7 +1566,7 @@ fil_tablespace_iterate(
 	dict_table_t*		table,
 	ulint			n_io_buffers,
 	PageCallback&		callback)
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /********************************************************************//**
 Looks for a pre-existing fil_space_t with the given tablespace ID
@@ -1575,16 +1626,71 @@ fil_node_next(
 @param[in]	new_table	new table
 @param[in]	tmp_name	temporary table name
 @param[in,out]	mtr		mini-transaction
- at return	whether the operation succeeded */
-bool
+ at return innodb error code */
+dberr_t
 fil_mtr_rename_log(
 	const dict_table_t*	old_table,
 	const dict_table_t*	new_table,
 	const char*		tmp_name,
 	mtr_t*			mtr)
-	MY_ATTRIBUTE((nonnull));
+	MY_ATTRIBUTE((warn_unused_result));
+
+/****************************************************************//**
+Acquire fil_system mutex */
+void
+fil_system_enter(void);
+/*==================*/
+/****************************************************************//**
+Release fil_system mutex */
+void
+fil_system_exit(void);
+/*==================*/
+
+/*******************************************************************//**
+Returns the table space by a given id, NULL if not found. */
+fil_space_t*
+fil_space_found_by_id(
+/*==================*/
+	ulint	id);	/*!< in: space id */
+
+/*******************************************************************//**
+Returns the table space by a given id, NULL if not found. */
+fil_space_t*
+fil_space_get_by_id(
+/*================*/
+	ulint	id);	/*!< in: space id */
+
+/******************************************************************
+Get id of first tablespace or ULINT_UNDEFINED if none */
+UNIV_INTERN
+ulint
+fil_get_first_space();
+/*=================*/
 
-/** Note that a non-predefined persistent tablespace has been modified
+/******************************************************************
+Get id of next tablespace or ULINT_UNDEFINED if none */
+UNIV_INTERN
+ulint
+fil_get_next_space(
+	ulint id);      /*!< in: space id */
+
+/******************************************************************
+Get id of first tablespace that has node or ULINT_UNDEFINED if none */
+UNIV_INTERN
+ulint
+fil_get_first_space_safe();
+/*======================*/
+
+/******************************************************************
+Get id of next tablespace that has node or ULINT_UNDEFINED if none */
+UNIV_INTERN
+ulint
+fil_get_next_space_safe(
+/*====================*/
+	ulint	id);	/*!< in: previous space id */
+
+
+/*******************************************************************//**
 by redo log.
 @param[in,out]	space	tablespace */
 void
@@ -1601,30 +1707,49 @@ fil_names_dirty_and_write(
 	fil_space_t*	space,
 	mtr_t*		mtr);
 
-/** Set the compression type for the tablespace
- at param[in] space		Space ID of tablespace for which to set
- at param[in] algorithm		Text representation of the algorithm
+/** Set the compression type for the tablespace of a table
+ at param[in]	table		Table that should be compressesed
+ at param[in]	algorithm	Text representation of the algorithm
 @return DB_SUCCESS or error code */
 dberr_t
 fil_set_compression(
-	ulint		space_id,
+	dict_table_t*	table,
 	const char*	algorithm)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
-/**
- at param[in]      space_id        Space ID to check
+/** Get the compression type for the tablespace
+ at param[in]	space_id	Space ID to check
 @return the compression algorithm */
 Compression::Type
 fil_get_compression(
-        ulint           space_id)
-	__attribute__((warn_unused_result));
+	ulint		space_id)
+	MY_ATTRIBUTE((warn_unused_result));
+
+/** Set the encryption type for the tablespace
+ at param[in] space		Space ID of tablespace for which to set
+ at param[in] algorithm		Encryption algorithm
+ at param[in] key			Encryption key
+ at param[in] iv			Encryption iv
+ at return DB_SUCCESS or error code */
+dberr_t
+fil_set_encryption(
+	ulint			space_id,
+	Encryption::Type	algorithm,
+	byte*			key,
+	byte*			iv)
+	MY_ATTRIBUTE((warn_unused_result));
+
+/**
+ at return true if the re-encrypt success */
+bool
+fil_encryption_rotate();
 
 /** Write MLOG_FILE_NAME records if a persistent tablespace was modified
 for the first time since the latest fil_names_clear().
 @param[in,out]	space	tablespace
 @param[in,out]	mtr	mini-transaction
 @return whether any MLOG_FILE_NAME record was written */
-inline __attribute__((warn_unused_result))
+inline MY_ATTRIBUTE((warn_unused_result))
 bool
 fil_names_write_if_was_clean(
 	fil_space_t*	space,
@@ -1701,72 +1826,6 @@ void fil_no_punch_hole(fil_node_t* node);
 void test_make_filepath();
 #endif /* UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH */
 
-/*******************************************************************//**
-Return space flags */
-UNIV_INLINE
-ulint
-fil_space_flags(
-/*===========*/
-	fil_space_t*	space);	/*!< in: space */
-
-#endif /* !UNIV_INNOCHECKSUM */
-
-/****************************************************************//**
-Acquire fil_system mutex */
-void
-fil_system_enter(void);
-/*==================*/
-/****************************************************************//**
-Release fil_system mutex */
-void
-fil_system_exit(void);
-/*==================*/
-
-#ifndef UNIV_INNOCHECKSUM
-/*******************************************************************//**
-Returns the table space by a given id, NULL if not found. */
-fil_space_t*
-fil_space_found_by_id(
-/*==================*/
-	ulint	id);	/*!< in: space id */
-
-/*******************************************************************//**
-Returns the table space by a given id, NULL if not found. */
-fil_space_t*
-fil_space_get_by_id(
-/*================*/
-	ulint	id);	/*!< in: space id */
-
-/******************************************************************
-Get id of first tablespace or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_first_space();
-/*=================*/
-
-/******************************************************************
-Get id of next tablespace or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_next_space(
-/*===============*/
-	ulint id);      /*!< in: space id */
-
-/******************************************************************
-Get id of first tablespace that has node or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_first_space_safe();
-/*======================*/
-
-/******************************************************************
-Get id of next tablespace that has node or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_next_space_safe(
-/*====================*/
-	ulint	id);	/*!< in: previous space id */
-
 
 /*******************************************************************//**
 Returns the block size of the file space
@@ -1779,15 +1838,24 @@ fil_space_get_block_size(
 	ulint   offset, /*!< in: page offset */
 	ulint   len);	/*!< in: page len */
 
-#endif /* UNIV_INNOCHECKSUM */
+/*******************************************************************//**
+Increments the count of pending operation, if space is not being deleted.
+ at return	TRUE if being deleted, and operation should be skipped */
+UNIV_INTERN
+ibool
+fil_inc_pending_ops(
+/*================*/
+	ulint	id,		/*!< in: space id */
+	ibool	print_err);	/*!< in: need to print error or not */
+/*******************************************************************//**
+Decrements the count of pending operations. */
+UNIV_INTERN
+void
+fil_decr_pending_ops(
+/*=================*/
+	ulint	id);	/*!< in: space id */
 
-/** Write the flushed LSN to the page header of the first page in the
-system tablespace.
- at param[in]	lsn	flushed LSN
- at return DB_SUCCESS or error number */
-dberr_t
-fil_write_flushed_lsn(
-	lsn_t	lsn);
+#endif /* UNIV_INNOCHECKSUM */
 
 #ifndef UNIV_INNOCHECKSUM
 #ifndef UNIV_NONINL
diff --git a/storage/innobase/include/fsp0file.h b/storage/innobase/include/fsp0file.h
index a08ebff..83aa370 100644
--- a/storage/innobase/include/fsp0file.h
+++ b/storage/innobase/include/fsp0file.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, 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
@@ -68,6 +68,8 @@ class Datafile {
 		m_atomic_write(),
 		m_last_os_error(),
 		m_file_info(),
+		m_encryption_key(NULL),
+		m_encryption_iv(NULL),
 		m_crypt_info()
 	{
 		/* No op */
@@ -92,6 +94,8 @@ class Datafile {
 		m_atomic_write(),
 		m_last_os_error(),
 		m_file_info(),
+		m_encryption_key(NULL),
+		m_encryption_iv(NULL),
 		m_crypt_info()
 	{
 		ut_ad(m_name != NULL);
@@ -114,6 +118,8 @@ class Datafile {
 		m_atomic_write(file.m_atomic_write),
 		m_last_os_error(),
 		m_file_info(),
+		m_encryption_key(NULL),
+		m_encryption_iv(NULL),
 		m_crypt_info()
 	{
 		m_name = mem_strdup(file.m_name);
@@ -172,6 +178,8 @@ class Datafile {
 		it should be reread if needed */
 		m_first_page_buf = NULL;
 		m_first_page = NULL;
+		m_encryption_key = NULL;
+		m_encryption_iv = NULL;
 		/* Do not copy crypt info it is read from first page */
 		m_crypt_info = NULL;
 
@@ -200,7 +208,7 @@ class Datafile {
 					are enforced.
 	@return DB_SUCCESS or error code */
 	virtual dberr_t open_read_write(bool read_only_mode)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Initialize OS specific file info. */
 	void init_file_info();
@@ -237,12 +245,14 @@ class Datafile {
 	successfully opened in order for this function to validate it.
 	@param[in]	space_id	The expected tablespace ID.
 	@param[in]	flags		The expected tablespace flags.
+	@param[in]	for_import	is it for importing
 	@retval DB_SUCCESS if tablespace is valid, DB_ERROR if not.
 	m_is_valid is also set true on success, else false. */
 	dberr_t validate_to_dd(
-		ulint	space_id,
-		ulint	flags)
-		__attribute__((warn_unused_result));
+		ulint		space_id,
+		ulint		flags,
+		bool		for_import)
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Validates this datafile for the purpose of recovery.
 	The file should exist and be successfully opened. We initially
@@ -253,19 +263,21 @@ class Datafile {
 	@retval DB_SUCCESS if tablespace is valid, DB_ERROR if not.
 	m_is_valid is also set true on success, else false. */
 	dberr_t validate_for_recovery()
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Checks the consistency of the first page of a datafile when the
 	tablespace is opened.  This occurs before the fil_space_t is created
 	so the Space ID found here must not already be open.
 	m_is_valid is set true on success, else false.
 	@param[out]	flush_lsn	contents of FIL_PAGE_FILE_FLUSH_LSN
+	@param[in]	for_import	if it is for importing
 	(only valid for the first file of the system tablespace)
 	@retval DB_SUCCESS on if the datafile is valid
 	@retval DB_CORRUPTION if the datafile is not readable
 	@retval DB_TABLESPACE_EXISTS if there is a duplicate space_id */
-	dberr_t validate_first_page(lsn_t* flush_lsn = 0)
-		__attribute__((warn_unused_result));
+	dberr_t validate_first_page(lsn_t*	flush_lsn,
+				    bool	for_import)
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Get Datafile::m_name.
 	@return m_name */
@@ -370,7 +382,7 @@ class Datafile {
 					are enforced.
 	@return DB_SUCCESS or error code */
 	dberr_t open_or_create(bool read_only_mode)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Reads a few significant fields from the first page of the
 	datafile, which must already be open.
@@ -378,7 +390,7 @@ class Datafile {
 					are enforced.
 	@return DB_SUCCESS or DB_IO_ERROR if page cannot be read */
 	dberr_t read_first_page(bool read_first_page)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Free the first page from memory when it is no longer needed. */
 	void free_first_page();
@@ -480,8 +492,14 @@ class Datafile {
 	struct stat			m_file_info;
 #endif	/* WIN32 */
 
+	/** Encryption key read from first page */
+	byte*			m_encryption_key;
+
+	/** Encryption iv read from first page */
+	byte*			m_encryption_iv;
+
 	/** Encryption information */
-	fil_space_crypt_t* m_crypt_info;
+	fil_space_crypt_t* 	m_crypt_info;
 };
 
 
@@ -551,7 +569,7 @@ class RemoteDatafile : public Datafile
 					are enforced.
 	@return DB_SUCCESS or error code */
 	dberr_t open_read_write(bool read_only_mode)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/******************************************************************
 	Global Static Functions;  Cannot refer to data members.
diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h
index 17be27a..3709c4a 100644
--- a/storage/innobase/include/fsp0fsp.h
+++ b/storage/innobase/include/fsp0fsp.h
@@ -42,6 +42,7 @@ Created 12/18/1995 Heikki Tuuri
 
 #endif /* !UNIV_INNOCHECKSUM */
 #include "fsp0types.h"
+
 #define FSP_FLAGS_POS_DATA_DIR_ORACLE	(FSP_FLAGS_POS_ATOMIC_BLOBS	\
 					+ FSP_FLAGS_WIDTH_ATOMIC_BLOBS  \
 					+ FSP_FLAGS_WIDTH_PAGE_SSIZE)
@@ -49,6 +50,7 @@ Created 12/18/1995 Heikki Tuuri
 #define FSP_FLAGS_MASK_DATA_DIR_ORACLE				\
 		((~(~0 << FSP_FLAGS_WIDTH_DATA_DIR))		\
 		<< FSP_FLAGS_POS_DATA_DIR_ORACLE)
+
 #define FSP_FLAGS_HAS_DATA_DIR_ORACLE(flags)			\
 		((flags & FSP_FLAGS_MASK_DATA_DIR_ORACLE)	\
 		>> FSP_FLAGS_POS_DATA_DIR_ORACLE)
@@ -118,6 +120,7 @@ descriptor page, but used only in the first. */
 					FSP_FREE_LIMIT at a time */
 /* @} */
 
+#ifndef UNIV_INNOCHECKSUM
 
 /* @defgroup File Segment Inode Constants (moved from fsp0fsp.c) @{ */
 
@@ -254,7 +257,6 @@ the extent are free and which contain old tuple version to clean. */
 
 /* @} */
 
-#ifndef UNIV_INNOCHECKSUM
 /**********************************************************************//**
 Initializes the file space system. */
 void
@@ -334,6 +336,40 @@ page_size_t
 fsp_header_get_page_size(
 	const page_t*	page);
 
+/** Decoding the encryption info
+from the first page of a tablespace.
+ at param[in/out]	key		key
+ at param[in/out]	iv		iv
+ at param[in]	encryption_info	encrytion info.
+ at return true if success */
+bool
+fsp_header_decode_encryption_info(
+	byte*		key,
+	byte*		iv,
+	byte*		encryption_info);
+
+/** Reads the encryption key from the first page of a tablespace.
+ at param[in]	fsp_flags	tablespace flags
+ at param[in/out]	key		tablespace key
+ at param[in/out]	iv		tablespace iv
+ at param[in]	page	first page of a tablespace
+ at return true if success */
+bool
+fsp_header_get_encryption_key(
+	ulint		fsp_flags,
+	byte*		key,
+	byte*		iv,
+	page_t*		page);
+
+/** Check the encryption key from the first page of a tablespace.
+ at param[in]	fsp_flags	tablespace flags
+ at param[in]	page		first page of a tablespace
+ at return true if success */
+bool
+fsp_header_check_encryption_key(
+	ulint			fsp_flags,
+	page_t*			page);
+
 /**********************************************************************//**
 Writes the space id and flags to a tablespace header.  The flags contain
 row type, physical/compressed page size, and logical/uncompressed page
@@ -346,6 +382,17 @@ fsp_header_init_fields(
 	ulint	flags);		/*!< in: tablespace flags (FSP_SPACE_FLAGS):
 				0, or table->flags if newer than COMPACT */
 
+/** Rotate the encryption info in the space header.
+ at param[in]	space		tablespace
+ at param[in]      encrypt_info	buffer for re-encrypt key.
+ at param[in,out]	mtr		mini-transaction
+ at return true if success. */
+bool
+fsp_header_rotate_encryption(
+	fil_space_t*		space,
+	byte*			encrypt_info,
+	mtr_t*			mtr);
+
 /** Initializes the space header of a new created space and creates also the
 insert buffer tree root if space == 0.
 @param[in]	space_id	space id
@@ -458,8 +505,8 @@ fseg_alloc_free_page_general(
 				If init_mtr!=mtr, but the page is already
 				latched in mtr, do not initialize the page. */
 	MY_ATTRIBUTE((warn_unused_result, nonnull));
-/**********************************************************************//**
-Reserves free pages from a tablespace. All mini-transactions which may
+
+/** Reserves free pages from a tablespace. All mini-transactions which may
 use several pages from the tablespace should call this function beforehand
 and reserve enough free extents so that they certainly will be able
 to do their operation, like a B-tree page split, fully. Reservations
@@ -478,23 +525,33 @@ The purpose is to avoid dead end where the database is full but the
 user cannot free any space because these freeing operations temporarily
 reserve some space.
 
-Single-table tablespaces whose size is < 32 pages are a special case. In this
-function we would liberally reserve several 64 page extents for every page
-split or merge in a B-tree. But we do not want to waste disk space if the table
-only occupies < 32 pages. That is why we apply different rules in that special
-case, just ensuring that there are 3 free pages available.
- at return TRUE if we were able to make the reservation */
+Single-table tablespaces whose size is < FSP_EXTENT_SIZE pages are a special
+case. In this function we would liberally reserve several extents for
+every page split or merge in a B-tree. But we do not want to waste disk space
+if the table only occupies < FSP_EXTENT_SIZE pages. That is why we apply
+different rules in that special case, just ensuring that there are n_pages
+free pages available.
+
+ at param[out]	n_reserved	number of extents actually reserved; if we
+				return true and the tablespace size is <
+				FSP_EXTENT_SIZE pages, then this can be 0,
+				otherwise it is n_ext
+ at param[in]	space_id	tablespace identifier
+ at param[in]	n_ext		number of extents to reserve
+ at param[in]	alloc_type	page reservation type (FSP_BLOB, etc)
+ at param[in,out]	mtr		the mini transaction
+ at param[in]	n_pages		for small tablespaces (tablespace size is
+				less than FSP_EXTENT_SIZE), number of free
+				pages to reserve.
+ at return true if we were able to make the reservation */
 bool
 fsp_reserve_free_extents(
-/*=====================*/
-	ulint*	n_reserved,/*!< out: number of extents actually reserved; if we
-			return TRUE and the tablespace size is < 64 pages,
-			then this can be 0, otherwise it is n_ext */
-	ulint	space_id,/*!< in: space id */
-	ulint	n_ext,	/*!< in: number of extents to reserve */
+	ulint*		n_reserved,
+	ulint		space_id,
+	ulint		n_ext,
 	fsp_reserve_t	alloc_type,
-			/*!< in: page reservation type */
-	mtr_t*	mtr);	/*!< in/out: mini-transaction */
+	mtr_t*		mtr,
+	ulint		n_pages = 2);
 
 /** Calculate how many KiB of new data we will be able to insert to the
 tablespace without running out of space.
@@ -551,7 +608,7 @@ fseg_free_step(
 	bool		ahi,	/*!< in: whether we may need to drop
 				the adaptive hash index */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**********************************************************************//**
 Frees part of a segment. Differs from fseg_free_step because this function
 leaves the header page unfreed.
@@ -564,7 +621,7 @@ fseg_free_step_not_header(
 	bool		ahi,	/*!< in: whether we may need to drop
 				the adaptive hash index */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Checks if a page address is an extent descriptor page address.
 @param[in]	page_id		page id
@@ -629,6 +686,7 @@ fsp_flags_are_equal(
 @param[in]	has_data_dir	This tablespace is in a remote location.
 @param[in]	is_shared	This tablespace can be shared by many tables.
 @param[in]	is_temporary	This tablespace is temporary.
+ at param[in]	is_encrypted	This tablespace is encrypted.
 @return tablespace flags after initialization */
 UNIV_INLINE
 ulint
@@ -640,7 +698,8 @@ fsp_flags_init(
 	bool			is_temporary,
 	bool			page_compression,
 	ulint			page_compression_level,
-	ulint			atomic_writes);
+	ulint			atomic_writes,
+	bool			is_encrypted = false);
 
 /** Convert a 32 bit integer tablespace flags to the 32 bit table flags.
 This can only be done for a tablespace that was built as a file-per-table
@@ -687,7 +746,7 @@ xdes_get_descriptor(
 	ulint			offset,
 	const page_size_t&	page_size,
 	mtr_t*			mtr)
-__attribute__((warn_unused_result));
+MY_ATTRIBUTE((warn_unused_result));
 
 /**********************************************************************//**
 Gets a descriptor bit of a page.
@@ -710,11 +769,11 @@ ulint
 xdes_calc_descriptor_page(
 	const page_size_t&	page_size,
 	ulint			offset);
-#endif /* !UNIV_INNOCHECKSUM */
 
+#endif /* !UNIV_INNOCHECKSUM */
 
-/*********************************************************************/
-/* @return offset into fsp header where crypt data is stored */
+/*********************************************************************//**
+ at return offset into fsp header where crypt data is stored */
 UNIV_INTERN
 ulint
 fsp_header_get_crypt_offset(
@@ -722,10 +781,9 @@ fsp_header_get_crypt_offset(
 	const page_size_t&	page_size,/*!< in: page size */
 	ulint* max_size);	/*!< out: free space after offset */
 
-#define fsp_page_is_free(space,page,mtr) \
-	fsp_page_is_free_func(space,page,mtr, __FILE__, __LINE__)
 
 #ifndef UNIV_INNOCHECKSUM
+
 /**********************************************************************//**
 Checks if a single page is free.
 @return	true if free */
@@ -738,7 +796,12 @@ fsp_page_is_free_func(
 	mtr_t*		mtr,		/*!< in/out: mini-transaction */
 	const char *file,
 	ulint line);
-#endif
+
+#define fsp_page_is_free(space,page,mtr)				\
+	fsp_page_is_free_func(space,page,mtr, __FILE__, __LINE__)
+
+#endif /* UNIV_INNOCHECKSUM */
+
 #ifndef UNIV_NONINL
 #include "fsp0fsp.ic"
 #endif
diff --git a/storage/innobase/include/fsp0fsp.ic b/storage/innobase/include/fsp0fsp.ic
index e204ac3..475dd23 100644
--- a/storage/innobase/include/fsp0fsp.ic
+++ b/storage/innobase/include/fsp0fsp.ic
@@ -1,7 +1,7 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, SkySQL Ab. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, 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
@@ -181,10 +181,11 @@ fsp_flags_set_page_size(
 @param[in]	has_data_dir	This tablespace is in a remote location.
 @param[in]	is_shared	This tablespace can be shared by many tables.
 @param[in]	is_temporary	This tablespace is temporary.
+ at param[in]	is_encrypted	This tablespace is encrypted.
 @param[in]	page_compressed Table uses page compression
 @param[in]	page_compression_level Page compression level
 @param[in]	atomic_writes	Table uses atomic writes
- at return tablespace flags after initialization */
+@@return tablespace flags after initialization */
 UNIV_INLINE
 ulint
 fsp_flags_init(
@@ -195,7 +196,8 @@ fsp_flags_init(
 	bool			is_temporary,
 	bool			page_compression,
 	ulint			page_compression_level,
-	ulint			atomic_writes)
+	ulint			atomic_writes,
+	bool			is_encrypted)
 {
 	ut_ad(page_size.physical() <= page_size.logical());
 	ut_ad(!page_size.is_compressed() || atomic_blobs);
@@ -229,6 +231,10 @@ fsp_flags_init(
 		flags |= FSP_FLAGS_MASK_TEMPORARY;
 	}
 
+	if (is_encrypted) {
+		flags |= FSP_FLAGS_MASK_ENCRYPTION;
+	}
+
 	/* In addition, tablespace flags also contain if the page
 	compression is used for this table. */
 	if (page_compression) {
@@ -247,6 +253,8 @@ fsp_flags_init(
 		flags |= FSP_FLAGS_SET_ATOMIC_WRITES(flags, atomic_writes);
 	}
 
+	ut_ad(fsp_flags_is_valid(flags));
+
 	return(flags);
 }
 
@@ -329,4 +337,15 @@ xdes_calc_descriptor_page(
 
 	return(ut_2pow_round(offset, page_size.physical()));
 }
+
+/** Calculates the descriptor array size.
+ at param[in]	page_size	page size
+ at return size of descriptor array */
+UNIV_INLINE
+ulint
+xdes_arr_size(
+	const page_size_t&	page_size)
+{
+	return(page_size.physical()/FSP_EXTENT_SIZE);
+}
 #endif /* !UNIV_INNOCHECKSUM */
diff --git a/storage/innobase/include/fsp0space.h b/storage/innobase/include/fsp0space.h
index 5fdb12a..603c71b 100644
--- a/storage/innobase/include/fsp0space.h
+++ b/storage/innobase/include/fsp0space.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, 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
@@ -100,7 +100,7 @@ class Tablespace {
 		m_path = mem_strdupl(path, len);
 		ut_ad(m_path != NULL);
 
-		os_normalize_path_for_win(m_path);
+		os_normalize_path(m_path);
 	}
 
 	/** Set tablespace path and filename members.
@@ -171,15 +171,24 @@ class Tablespace {
 	/** Free the memory allocated by the Tablespace object */
 	void shutdown();
 
-	/**
-	@return ULINT_UNDEFINED if the size is invalid else the sum of sizes */
-	ulint get_sum_of_sizes() const;
+	/** @return the sum of the file sizes of each Datafile */
+	ulint get_sum_of_sizes() const
+	{
+		ulint	sum = 0;
+
+		for (files_t::const_iterator it = m_files.begin();
+		     it != m_files.end(); ++it) {
+			sum += it->m_size;
+		}
+
+		return(sum);
+	}
 
 	/** Open or Create the data files if they do not exist.
 	@param[in]	is_temp	whether this is a temporary tablespace
 	@return DB_SUCCESS or error code */
 	dberr_t open_or_create(bool is_temp)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Delete all the data files. */
 	void delete_files();
diff --git a/storage/innobase/include/fsp0sysspace.h b/storage/innobase/include/fsp0sysspace.h
index 42778f7..226d53e 100644
--- a/storage/innobase/include/fsp0sysspace.h
+++ b/storage/innobase/include/fsp0sysspace.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, 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
@@ -152,6 +152,15 @@ class SysTablespace : public Tablespace
 		       * ((1024 * 1024) / UNIV_PAGE_SIZE));
 	}
 
+	/** Roundoff to MegaBytes is similar as done in
+	SysTablespace::parse_units() function.
+	@return the pages when given size of file (bytes). */
+	ulint get_pages_from_size(os_offset_t size)
+	{
+		return (ulint)((size / (1024 * 1024))
+			       * ((1024 * 1024) / UNIV_PAGE_SIZE));
+	}
+
 	/**
 	@return next increment size */
 	ulint get_increment() const;
@@ -167,7 +176,7 @@ class SysTablespace : public Tablespace
 		bool	create_new_db,
 		ulint*	sum_new_sizes,
 		lsn_t*	flush_lsn)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 private:
 	/** Check the tablespace header for this tablespace.
@@ -289,17 +298,6 @@ is_system_tablespace(
 	       || id == srv_tmp_space.space_id());
 }
 
-/** Check if it is a shared tablespace.
- at param[in]	id	Space ID to check
- at return true if id is a shared tablespace, false if not. */
-UNIV_INLINE
-bool
-is_shared_tablespace(
-	ulint	id)
-{
-	return(is_system_tablespace(id));
-}
-
 /** Check if shared-system or undo tablespace.
 @return true if shared-system or undo tablespace */
 UNIV_INLINE
diff --git a/storage/innobase/include/fsp0types.h b/storage/innobase/include/fsp0types.h
index 33f630a..73fd634 100644
--- a/storage/innobase/include/fsp0types.h
+++ b/storage/innobase/include/fsp0types.h
@@ -1,6 +1,7 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, 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
@@ -62,7 +63,7 @@ page size | file space extent size
 #define	FSP_EXTENT_SIZE_MAX	(4194304 / UNIV_PAGE_SIZE_MAX)
 
 /** File space extent size (one megabyte) in pages for MIN page size */
-#define	FSP_EXTENT_SIZE_MIN	(1048576U / UNIV_PAGE_SIZE_MIN)
+#define	FSP_EXTENT_SIZE_MIN	(1048576 / UNIV_PAGE_SIZE_MIN)
 
 /** On a page of any file segment, data may be put starting from this
 offset */
@@ -190,7 +191,7 @@ so they should have a file format number plus the DICT_TF_COMPACT bit set.
 bool
 fsp_flags_is_valid(
 	ulint	flags)
-	__attribute__((warn_unused_result, const));
+	MY_ATTRIBUTE((warn_unused_result, const));
 
 /** Check if tablespace is system temporary.
 @param[in]      space_id        verify is checksum is enabled for given space.
@@ -249,6 +250,9 @@ was created with CREATE TABLESPACE and can be shared by multiple tables. */
 is a temporary tablespace and everything in it is temporary, meaning that
 it is for a single client and should be deleted upon startup if it exists. */
 #define FSP_FLAGS_WIDTH_TEMPORARY	1
+/** Width of the encryption flag.  This flag indicates that the tablespace
+is a tablespace with encryption. */
+#define FSP_FLAGS_WIDTH_ENCRYPTION	1
 
 /** Number of flag bits used to indicate the page compression and compression level */
 #define FSP_FLAGS_WIDTH_PAGE_COMPRESSION  1
@@ -265,6 +269,7 @@ it is for a single client and should be deleted upon startup if it exists. */
 				+ FSP_FLAGS_WIDTH_DATA_DIR	\
 				+ FSP_FLAGS_WIDTH_SHARED	\
 				+ FSP_FLAGS_WIDTH_TEMPORARY	\
+				+ FSP_FLAGS_WIDTH_ENCRYPTION	\
 				+ FSP_FLAGS_WIDTH_PAGE_COMPRESSION \
 				+ FSP_FLAGS_WIDTH_PAGE_COMPRESSION_LEVEL \
 				+ FSP_FLAGS_WIDTH_ATOMIC_WRITES )
@@ -292,9 +297,12 @@ it is for a single client and should be deleted upon startup if it exists. */
 /** Zero relative shift position of the start of the TEMPORARY bit */
 #define FSP_FLAGS_POS_TEMPORARY		(FSP_FLAGS_POS_SHARED		\
 					+ FSP_FLAGS_WIDTH_SHARED)
-/** Zero relative shift position of the PAGE_COMPRESSION field */
-#define FSP_FLAGS_POS_PAGE_COMPRESSION	(FSP_FLAGS_POS_TEMPORARY	\
+/** Zero relative shift position of the start of the ENCRYPTION bit */
+#define FSP_FLAGS_POS_ENCRYPTION	(FSP_FLAGS_POS_TEMPORARY	\
 					+ FSP_FLAGS_WIDTH_TEMPORARY)
+/** Zero relative shift position of the PAGE_COMPRESSION field */
+#define FSP_FLAGS_POS_PAGE_COMPRESSION	(FSP_FLAGS_POS_ENCRYPTION	\
+					+ FSP_FLAGS_WIDTH_ENCRYPTION)
 /** Zero relative shift position of the PAGE_COMPRESSION_LEVEL field */
 #define FSP_FLAGS_POS_PAGE_COMPRESSION_LEVEL	(FSP_FLAGS_POS_PAGE_COMPRESSION	\
 					+ FSP_FLAGS_WIDTH_PAGE_COMPRESSION)
@@ -302,8 +310,8 @@ it is for a single client and should be deleted upon startup if it exists. */
 #define FSP_FLAGS_POS_ATOMIC_WRITES	(FSP_FLAGS_POS_PAGE_COMPRESSION_LEVEL	\
 					+ FSP_FLAGS_WIDTH_PAGE_COMPRESSION_LEVEL)
 /** Zero relative shift position of the start of the UNUSED bits */
-#define FSP_FLAGS_POS_UNUSED		(FSP_FLAGS_POS_PAGE_COMPRESSION_LEVEL	\
-					+ FSP_FLAGS_WIDTH_PAGE_COMPRESSION_LEVEL)
+#define FSP_FLAGS_POS_UNUSED		(FSP_FLAGS_POS_ATOMIC_WRITES	\
+					+ FSP_FLAGS_WIDTH_ATOMIC_WRITES)
 
 
 /** Bit mask of the POST_ANTELOPE field */
@@ -334,6 +342,10 @@ it is for a single client and should be deleted upon startup if it exists. */
 #define FSP_FLAGS_MASK_TEMPORARY				\
 		((~(~0U << FSP_FLAGS_WIDTH_TEMPORARY))		\
 		<< FSP_FLAGS_POS_TEMPORARY)
+/** Bit mask of the ENCRYPTION field */
+#define FSP_FLAGS_MASK_ENCRYPTION				\
+		((~(~0U << FSP_FLAGS_WIDTH_ENCRYPTION))		\
+		<< FSP_FLAGS_POS_ENCRYPTION)
 /** Bit mask of the PAGE_COMPRESSION field */
 #define FSP_FLAGS_MASK_PAGE_COMPRESSION			\
 		((~(~0 << FSP_FLAGS_WIDTH_PAGE_COMPRESSION))	\
@@ -375,6 +387,10 @@ it is for a single client and should be deleted upon startup if it exists. */
 #define FSP_FLAGS_GET_TEMPORARY(flags)				\
 		((flags & FSP_FLAGS_MASK_TEMPORARY)		\
 		>> FSP_FLAGS_POS_TEMPORARY)
+/** Return the contents of the ENCRYPTION field */
+#define FSP_FLAGS_GET_ENCRYPTION(flags)				\
+		((flags & FSP_FLAGS_MASK_ENCRYPTION)		\
+		>> FSP_FLAGS_POS_ENCRYPTION)
 /** Return the contents of the UNUSED bits */
 #define FSP_FLAGS_GET_UNUSED(flags)				\
 		(flags >> FSP_FLAGS_POS_UNUSED)
diff --git a/storage/innobase/include/fts0ast.h b/storage/innobase/include/fts0ast.h
index f0f00a4..87b7cf7 100644
--- a/storage/innobase/include/fts0ast.h
+++ b/storage/innobase/include/fts0ast.h
@@ -195,6 +195,13 @@ fts_ast_state_free(
 /*===============*/
 	fts_ast_state_t*state);			/*!< in: state instance
 						to free */
+/** Check only union operation involved in the node
+ at param[in]	node	ast node to check
+ at return true if the node contains only union else false. */
+bool
+fts_ast_node_check_union(
+	fts_ast_node_t*	node);
+
 /******************************************************************//**
 Traverse the AST - in-order traversal.
 @return DB_SUCCESS if all went well */
diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h
index 210b9b7..2d25647 100644
--- a/storage/innobase/include/fts0fts.h
+++ b/storage/innobase/include/fts0fts.h
@@ -66,7 +66,7 @@ optimize using a 4 byte Doc ID for FIC merge sort to reduce sort size */
 #define MAX_DOC_ID_OPT_VAL		1073741824
 
 /** Document id type. */
-typedef ib_uint64_t doc_id_t;
+typedef ib_id_t doc_id_t;
 
 /** doc_id_t printf format */
 #define FTS_DOC_ID_FORMAT	IB_ID_FMT
@@ -103,7 +103,6 @@ those defined in mysql file ft_global.h */
 should not exceed FTS_DOC_ID_MAX_STEP */
 #define FTS_DOC_ID_MAX_STEP		65535
 
-
 /** Maximum possible Fulltext word length */
 #define FTS_MAX_WORD_LEN		HA_FT_MAXBYTELEN
 
@@ -128,6 +127,7 @@ should not exceed FTS_DOC_ID_MAX_STEP */
 /* BLOB COLUMN, 0 means VARIABLE SIZE */
 #define FTS_INDEX_ILIST_LEN		0
 
+
 /** Variable specifying the FTS parallel sort degree */
 extern ulong		fts_sort_pll_degree;
 
@@ -515,7 +515,7 @@ fts_create_common_tables(
 						index */
 	const char*	name,			/*!< in: table name */
 	bool		skip_doc_id_index)	/*!< in: Skip index on doc id */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************************//**
 Wrapper function of fts_create_index_tables_low(), create auxiliary
 tables for an FTS index
@@ -526,7 +526,7 @@ fts_create_index_tables(
 	trx_t*			trx,		/*!< in: transaction handle */
 	const dict_index_t*	index)		/*!< in: the FTS index
 						instance */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************************//**
 Creates the column specific ancillary tables needed for supporting an
 FTS index on the given table. row_mysql_lock_data_dictionary must have
@@ -541,15 +541,14 @@ fts_create_index_tables_low(
 						instance */
 	const char*	table_name,		/*!< in: the table name */
 	table_id_t	table_id)		/*!< in: the table id */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************************//**
 Add the FTS document id hidden column. */
 void
 fts_add_doc_id_column(
 /*==================*/
 	dict_table_t*	table,	/*!< in/out: Table with FTS index */
-	mem_heap_t*	heap)	/*!< in: temporary memory heap, or NULL */
-	MY_ATTRIBUTE((nonnull(1)));
+	mem_heap_t*	heap);	/*!< in: temporary memory heap, or NULL */
 
 /*********************************************************************//**
 Drops the ancillary tables needed for supporting an FTS index on the
@@ -560,9 +559,8 @@ dberr_t
 fts_drop_tables(
 /*============*/
 	trx_t*		trx,			/*!< in: transaction */
-	dict_table_t*	table)			/*!< in: table has the FTS
+	dict_table_t*	table);			/*!< in: table has the FTS
 						index */
-	MY_ATTRIBUTE((nonnull));
 /******************************************************************//**
 The given transaction is about to be committed; do whatever is necessary
 from the FTS system's POV.
@@ -571,23 +569,27 @@ dberr_t
 fts_commit(
 /*=======*/
 	trx_t*		trx)			/*!< in: transaction */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
-
-/*******************************************************************//**
-FTS Query entry point.
+	MY_ATTRIBUTE((warn_unused_result));
+
+/** FTS Query entry point.
+ at param[in]	trx		transaction
+ at param[in]	index		fts index to search
+ at param[in]	flags		FTS search mode
+ at param[in]	query_str	FTS query
+ at param[in]	query_len	FTS query string len in bytes
+ at param[in,out]	result		result doc ids
+ at param[in]	limit		limit value
 @return DB_SUCCESS if successful otherwise error code */
 dberr_t
 fts_query(
-/*======*/
-	trx_t*		trx,			/*!< in: transaction */
-	dict_index_t*	index,			/*!< in: FTS index to search */
-	uint		flags,			/*!< in: FTS search mode */
-	const byte*	query,			/*!< in: FTS query */
-	ulint		query_len,		/*!< in: FTS query string len
-						in bytes */
-	fts_result_t**	result)			/*!< out: query result, to be
-						freed by the caller.*/
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	trx_t*		trx,
+	dict_index_t*	index,
+	uint		flags,
+	const byte*	query_str,
+	ulint		query_len,
+	fts_result_t**	result,
+	ulonglong	limit)
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Retrieve the FTS Relevance Ranking result for doc with doc_id
@@ -704,8 +706,7 @@ Run OPTIMIZE on the given table.
 dberr_t
 fts_optimize_table(
 /*===============*/
-	dict_table_t*	table)			/*!< in: table to optimiza */
-	MY_ATTRIBUTE((nonnull));
+	dict_table_t*	table);			/*!< in: table to optimiza */
 
 /**********************************************************************//**
 Startup the optimize thread and create the work queue. */
@@ -728,7 +729,7 @@ fts_drop_index_tables(
 /*==================*/
 	trx_t*		trx,			/*!< in: transaction */
 	dict_index_t*	index)			/*!< in: Index to drop */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Remove the table from the OPTIMIZER's list. We do wait for
@@ -738,41 +739,32 @@ fts_optimize_remove_table(
 /*======================*/
 	dict_table_t*	table);			/*!< in: table to remove */
 
+/** Shutdown fts optimize thread. */
+void
+fts_optimize_shutdown();
+
 /** Send sync fts cache for the table.
 @param[in]	table	table to sync */
-UNIV_INTERN
 void
 fts_optimize_request_sync_table(
 	dict_table_t*	table);
 
 /**********************************************************************//**
-Signal the optimize thread to prepare for shutdown. */
-void
-fts_optimize_start_shutdown(void);
-/*==============================*/
-
-/**********************************************************************//**
-Inform optimize to clean up. */
-void
-fts_optimize_end(void);
-/*===================*/
-
-/**********************************************************************//**
 Take a FTS savepoint. */
 void
 fts_savepoint_take(
 /*===============*/
 	trx_t*		trx,			/*!< in: transaction */
 	fts_trx_t*	fts_trx,		/*!< in: fts transaction */
-	const char*	name)			/*!< in: savepoint name */
-	MY_ATTRIBUTE((nonnull));
+	const char*	name);			/*!< in: savepoint name */
+
 /**********************************************************************//**
 Refresh last statement savepoint. */
 void
 fts_savepoint_laststmt_refresh(
 /*===========================*/
-	trx_t*		trx)			/*!< in: transaction */
-	MY_ATTRIBUTE((nonnull));
+	trx_t*		trx);			/*!< in: transaction */
+
 /**********************************************************************//**
 Release the savepoint data identified by  name. */
 void
@@ -832,19 +824,21 @@ fts_drop_index_split_tables(
 /*========================*/
 	trx_t*		trx,			/*!< in: transaction */
 	dict_index_t*	index)			/*!< in: fts instance */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Run SYNC on the table, i.e., write out data from the cache to the
 FTS auxiliary INDEX table and clear the cache at the end.
 @param[in,out]	table		fts table
 @param[in]	unlock_cache	whether unlock cache when write node
 @param[in]	wait		whether wait for existing sync to finish
+ at param[in]      has_dict        whether has dict operation lock
 @return DB_SUCCESS on success, error code on failure. */
 dberr_t
 fts_sync_table(
 	dict_table_t*	table,
 	bool		unlock_cache,
-	bool		wait);
+	bool		wait,
+	bool		has_dict);
 
 /****************************************************************//**
 Free the query graph but check whether dict_sys->mutex is already
@@ -1027,8 +1021,7 @@ fts_drop_index(
 /*===========*/
 	dict_table_t*	table,	/*!< in: Table where indexes are dropped */
 	dict_index_t*	index,	/*!< in: Index to be dropped */
-	trx_t*		trx)	/*!< in: Transaction for the drop */
-	MY_ATTRIBUTE((nonnull));
+	trx_t*		trx);	/*!< in: Transaction for the drop */
 
 /****************************************************************//**
 Rename auxiliary tables for all fts index for a table
@@ -1053,12 +1046,12 @@ fts_check_cached_index(
 consistent state. For now consistency is check only by ensuring
 index->page_no != FIL_NULL
 @param[out]	base_table	table has host fts index
- at param[in,out]	trx		trx handler
- at return true if check certifies auxillary tables are sane false otherwise. */
-bool
-fts_is_corrupt(
+ at param[in,out]	trx		trx handler */
+void
+fts_check_corrupt(
 	dict_table_t*	base_table,
 	trx_t*		trx);
 
+
 #endif /*!< fts0fts.h */
 
diff --git a/storage/innobase/include/fts0priv.h b/storage/innobase/include/fts0priv.h
index f7a2d2c..1fd33c2 100644
--- a/storage/innobase/include/fts0priv.h
+++ b/storage/innobase/include/fts0priv.h
@@ -121,7 +121,7 @@ fts_parse_sql(
 	fts_table_t*	fts_table,	/*!< in: FTS aux table */
 	pars_info_t*	info,		/*!< in: info struct, or NULL */
 	const char*	sql)		/*!< in: SQL string to evaluate */
-	MY_ATTRIBUTE((nonnull(3), malloc, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Evaluate a parsed SQL statement
@@ -131,7 +131,7 @@ fts_eval_sql(
 /*=========*/
 	trx_t*		trx,		/*!< in: transaction */
 	que_t*		graph)		/*!< in: Parsed statement */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Construct the name of an ancillary FTS table for the given table.
@@ -140,8 +140,9 @@ for param 'table_name'. */
 void
 fts_get_table_name(
 /*===============*/
-	const fts_table_t*	fts_table,	/*!< in: FTS aux table info */
-	char*			table_name);	/*!< in/out: aux table name */
+	const fts_table_t*
+			fts_table,	/*!< in: FTS aux table info */
+	char*		table_name);	/*!< in/out: aux table name */
 
 /******************************************************************//**
 Construct the column specification part of the SQL string for selecting the
@@ -164,7 +165,7 @@ fts_get_select_columns_str(
 	dict_index_t*	index,		/*!< in: FTS index */
 	pars_info_t*	info,		/*!< in/out: parser info */
 	mem_heap_t*	heap)		/*!< in: memory heap */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** define for fts_doc_fetch_by_doc_id() "option" value, defines whether
 we want to get Doc whose ID is equal to or greater or smaller than supplied
@@ -189,8 +190,7 @@ fts_doc_fetch_by_doc_id(
 	fts_sql_callback
 			callback,	/*!< in: callback to read
 					records */
-	void*		arg)		/*!< in: callback arg */
-	MY_ATTRIBUTE((nonnull(6)));
+	void*		arg);		/*!< in: callback arg */
 
 /*******************************************************************//**
 Callback function for fetch that stores the text of an FTS document,
@@ -200,8 +200,8 @@ ibool
 fts_query_expansion_fetch_doc(
 /*==========================*/
 	void*		row,		/*!< in: sel_node_t* */
-	void*		user_arg)	/*!< in: fts_doc_t* */
-	MY_ATTRIBUTE((nonnull));
+	void*		user_arg);	/*!< in: fts_doc_t* */
+
 /********************************************************************
 Write out a single word's data as new entry/entries in the INDEX table.
 @return DB_SUCCESS if all OK. */
@@ -213,7 +213,7 @@ fts_write_node(
 	fts_table_t*	fts_table,	/*!< in: the FTS aux index */
 	fts_string_t*	word,		/*!< in: word in UTF-8 */
 	fts_node_t*	node)		/*!< in: node columns */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Check fts token
 1. for ngram token, check whether the token contains any words in stopwords
@@ -274,7 +274,7 @@ fts_bsearch(
 	int		lower,		/*!< in: lower bound of array*/
 	int		upper,		/*!< in: upper bound of array*/
 	doc_id_t	doc_id)		/*!< in: doc id to lookup */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************************//**
 Free document. */
 void
@@ -359,7 +359,7 @@ fts_parse_sql_no_dict_lock(
 	fts_table_t*	fts_table,	/*!< in: table with FTS index */
 	pars_info_t*	info,		/*!< in: parser info */
 	const char*	sql)		/*!< in: SQL string to evaluate */
-	MY_ATTRIBUTE((nonnull(3), malloc, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Get value from config table. The caller must ensure that enough
@@ -388,7 +388,7 @@ fts_config_get_index_value(
 					this parameter name */
 	fts_string_t*	value)		/*!< out: value read from
 					config table */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Set the value in the config table for name.
@@ -413,7 +413,7 @@ fts_config_set_ulint(
 	fts_table_t*	fts_table,	/*!< in: the indexed FTS table */
 	const char*	name,		/*!< in: param name */
 	ulint		int_value)	/*!< in: value */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Set the value specific to an FTS index in the config table.
@@ -427,7 +427,7 @@ fts_config_set_index_value(
 					this parameter name */
 	fts_string_t*	value)		/*!< out: value read from
 					config table */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Increment the value in the config table for column name.
@@ -440,7 +440,7 @@ fts_config_increment_value(
 	const char*	name,		/*!< in: increment config value
 					for this parameter name */
 	ulint		delta)		/*!< in: increment by this much */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Increment the per index value in the config table for column name.
@@ -464,7 +464,7 @@ fts_config_get_index_ulint(
 	dict_index_t*	index,		/*!< in: FTS index */
 	const char*	name,		/*!< in: param name */
 	ulint*		int_value)	/*!< out: value */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Set an ulint value int the config table.
@@ -476,7 +476,7 @@ fts_config_set_index_ulint(
 	dict_index_t*	index,		/*!< in: FTS index */
 	const char*	name,		/*!< in: param name */
 	ulint		int_value)	/*!< in: value */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Get an ulint value from the config table.
@@ -499,7 +499,7 @@ fts_cache_find_word(
 			index_cache,	/*!< in: cache to search */
 	const fts_string_t*
 			text)		/*!< in: word to search for */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Check cache for deleted doc id.
@@ -510,7 +510,7 @@ fts_cache_is_deleted_doc_id(
 	const fts_cache_t*
 			cache,		/*!< in: cache ito search */
 	doc_id_t	doc_id)		/*!< in: doc id to search for */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Append deleted doc ids to vector and sort the vector. */
@@ -543,7 +543,7 @@ fts_get_total_word_count(
 	trx_t*		trx,		/*!< in: transaction */
 	dict_index_t*	index,		/*!< in: for this index */
 	ulint*		total)		/*!< out: total words */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 #endif
 /******************************************************************//**
 Search the index specific cache for a particular FTS index.
@@ -555,7 +555,7 @@ fts_find_index_cache(
 			cache,		/*!< in: cache to search */
 	const dict_index_t*
 			index)		/*!< in: index to search for */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Write the table id to the given buffer (including final NUL). Buffer must be
@@ -567,10 +567,10 @@ fts_write_object_id(
 /*================*/
 	ib_id_t		id,		/*!< in: a table/index id */
 	char*		str,		/*!< in: buffer to write the id to */
-	bool		hex_format MY_ATTRIBUTE((unused)))
+	bool		hex_format MY_ATTRIBUTE((unused)));
 					/*!< in: true for fixed hex format,
 					false for old ambiguous format */
-	MY_ATTRIBUTE((nonnull));
+
 /******************************************************************//**
 Read the table id from the string generated by fts_write_object_id().
 @return TRUE if parse successful */
@@ -580,7 +580,7 @@ fts_read_object_id(
 /*===============*/
 	ib_id_t*	id,		/*!< out: a table id */
 	const char*	str)		/*!< in: buffer to read from */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Get the table id.
@@ -593,7 +593,7 @@ fts_get_table_id(
 	char*		table_id)	/*!< out: table id, must be at least
 					FTS_AUX_MIN_TABLE_ID_LENGTH bytes
 					long */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Add the table to add to the OPTIMIZER's list. */
@@ -617,7 +617,7 @@ fts_get_table_name_prefix(
 /*======================*/
 	const fts_table_t*
 			fts_table)	/*!< in: Auxiliary table type */
-	MY_ATTRIBUTE((nonnull, malloc, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Add node positions. */
@@ -637,7 +637,7 @@ fts_config_create_index_param_name(
 /*===============================*/
 	const char*		param,	/*!< in: base name of param */
 	const dict_index_t*	index)	/*!< in: index for config */
-	MY_ATTRIBUTE((nonnull, malloc, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 #ifndef UNIV_NONINL
 #include "fts0priv.ic"
diff --git a/storage/innobase/include/fts0priv.ic b/storage/innobase/include/fts0priv.ic
index 9de3be2..fa2cdd4 100644
--- a/storage/innobase/include/fts0priv.ic
+++ b/storage/innobase/include/fts0priv.ic
@@ -46,31 +46,26 @@ fts_write_object_id(
 	/* Use this to construct old(5.6.14 and 5.7.3) windows
 	ambiguous aux table names */
 	DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name",
-			return(sprintf(str, "%016llu", id)););
+			return(sprintf(str, "%016llu", (ulonglong) id)););
 
 #else /* _WIN32 */
 
 	/* Use this to construct old(5.6.14 and 5.7.3) windows
 	ambiguous aux table names */
 	DBUG_EXECUTE_IF("innodb_test_wrong_windows_fts_aux_table_name",
-			return(sprintf(str, "%016lu", id)););
+			return(sprintf(str, "%016llu", (ulonglong) id)););
 
 	DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name",
-			return(sprintf(str, "%016lx", id)););
+			return(sprintf(str, "%016llx", (ulonglong) id)););
 
 #endif /* _WIN32 */
 
 	/* As above, but this is only for those tables failing to rename. */
 	if (!hex_format) {
-#ifdef _WIN32
-		// FIXME: Use ut_snprintf(), so does following one.
-		return(sprintf(str, "%016llu", id));
-#else /* _WIN32 */
-		return(sprintf(str, "%016lu", id));
-#endif /* _WIN32 */
+		return(sprintf(str, "%016llu", (ulonglong) id));
 	}
 
-	return(sprintf(str, "%016lx", id));
+	return(sprintf(str, "%016llx", (ulonglong) id));
 }
 
 /******************************************************************//**
@@ -86,7 +81,7 @@ fts_read_object_id(
 	/* NOTE: this func doesn't care about whether current table
 	is set with HEX_NAME, the user of the id read here will check
 	if the id is HEX or DEC and do the right thing with it. */
-	return(sscanf(str, "%016lx", id) == 1);
+	return(sscanf(str, UINT64PFx, id) == 1);
 }
 
 /******************************************************************//**
diff --git a/storage/innobase/include/fut0fut.h b/storage/innobase/include/fut0fut.h
index ab04a70..0b8b8b0 100644
--- a/storage/innobase/include/fut0fut.h
+++ b/storage/innobase/include/fut0fut.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, 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
@@ -50,7 +50,7 @@ fut_get_ptr(
 	rw_lock_type_t		rw_latch,
 	mtr_t*			mtr,
 	buf_block_t**		ptr_block = NULL)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 #ifndef UNIV_NONINL
 #include "fut0fut.ic"
diff --git a/storage/innobase/include/gis0rtree.h b/storage/innobase/include/gis0rtree.h
index 316cab8..436374f 100644
--- a/storage/innobase/include/gis0rtree.h
+++ b/storage/innobase/include/gis0rtree.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2014, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, 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
@@ -70,7 +70,7 @@ Created 2013/03/27 Jimmy Yang and Allen Lai
 
 /* Define it for rtree search mode checking. */
 #define RTREE_SEARCH_MODE(mode)					\
-	(((mode) >= PAGE_CUR_CONTAIN) && ((mode <= PAGE_CUR_RTREE_LOCATE)))
+	(((mode) >= PAGE_CUR_CONTAIN) && ((mode <= PAGE_CUR_RTREE_GET_FATHER)))
 
 /* Geometry data header */
 #define	GEO_DATA_HEADER_SIZE	4
@@ -320,6 +320,23 @@ rtr_get_mbr_from_tuple(
 #define rtr_page_get_father_node_ptr(of,heap,sea,cur,mtr)		\
 	rtr_page_get_father_node_ptr_func(of,heap,sea,cur,__FILE__,__LINE__,mtr)
 
+/* Get the rtree page father.
+ at param[in]	offsets		work area for the return value
+ at param[in]	index		rtree index
+ at param[in]	block		child page in the index
+ at param[in]	mtr		mtr
+ at param[in]	sea_cur		search cursor, contains information
+				about parent nodes in search
+ at param[in]	cursor		cursor on node pointer record,
+				its page x-latched */
+void
+rtr_page_get_father(
+	dict_index_t*	index,
+	buf_block_t*	block,
+	mtr_t*		mtr,
+	btr_cur_t*	sea_cur,
+	btr_cur_t*	cursor);
+
 /************************************************************//**
 Returns the upper level node pointer to a R-Tree page. It is assumed
 that mtr holds an x-latch on the tree.
diff --git a/storage/innobase/include/ha0ha.h b/storage/innobase/include/ha0ha.h
index 11c12c4..15a99dd 100644
--- a/storage/innobase/include/ha0ha.h
+++ b/storage/innobase/include/ha0ha.h
@@ -211,7 +211,7 @@ struct ha_node_t {
 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
 	buf_block_t*	block;	/*!< buffer block containing the data, or NULL */
 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
-        const rec_t*	data;	/*!< pointer to the data */
+	const rec_t*	data;	/*!< pointer to the data */
 };
 
 #ifdef UNIV_DEBUG
diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h
index 9bf8cd2..837c377f 100644
--- a/storage/innobase/include/ha_prototypes.h
+++ b/storage/innobase/include/ha_prototypes.h
@@ -37,6 +37,7 @@ simple headers.
 class THD;
 class Field;
 struct fts_string_t;
+//typedef struct charset_info_st CHARSET_INFO;
 
 /*********************************************************************//**
 Wrapper around MySQL's copy_and_convert function.
@@ -162,7 +163,7 @@ checkpoint when necessary.*/
 UNIV_INTERN
 void
 innobase_mysql_log_notify(
-/*===============*/
+/*======================*/
 	ib_uint64_t	write_lsn,	/*!< in: LSN written to log file */
 	ib_uint64_t	flush_lsn);	/*!< in: LSN flushed to disk */
 
@@ -342,6 +343,14 @@ thd_set_lock_wait_time(
 	THD*	thd,	/*!< in/out: thread handle */
 	ulint	value);	/*!< in: time waited for the lock */
 
+/** Get status of innodb_tmpdir.
+ at param[in]	thd	thread handle, or NULL to query
+			the global innodb_tmpdir.
+ at retval NULL if innodb_tmpdir="" */
+const char*
+thd_innodb_tmpdir(
+	THD*	thd);
+
 /**********************************************************************//**
 Get the current setting of the table_cache_size global parameter. We do
 a dirty read because for one there is no synchronization object and
@@ -531,7 +540,6 @@ innobase_convert_to_system_charset(
 	const char*     from,		/* in: identifier to convert */
 	ulint           len,		/* in: length of 'to', in bytes */
 	uint*		errors);	/* out: error return */
-
 /**********************************************************************
 Check if the length of the identifier exceeds the maximum allowed.
 The input to this function is an identifier in charset my_charset_filename.
@@ -606,7 +614,7 @@ ICP_RESULT
 innobase_index_cond(
 /*================*/
 	void*	file)	/*!< in/out: pointer to ha_innobase */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************************//**
 Gets information on the durability property requested by thread.
@@ -625,7 +633,7 @@ enum durability_properties
 thd_requested_durability(
 /*=====================*/
 	const THD* thd)	/*!< in: thread handle */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Update the system variable with the given value of the InnoDB
 buffer pool size.
diff --git a/storage/innobase/include/ibuf0ibuf.h b/storage/innobase/include/ibuf0ibuf.h
index c4d8383..f3fd5e9 100644
--- a/storage/innobase/include/ibuf0ibuf.h
+++ b/storage/innobase/include/ibuf0ibuf.h
@@ -244,7 +244,7 @@ ibool
 ibuf_inside(
 /*========*/
 	const mtr_t*	mtr)	/*!< in: mini-transaction */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Checks if a page address is an ibuf bitmap page (level 3 page) address.
 @param[in]	page_id		page id
@@ -362,20 +362,16 @@ ibuf_delete_for_discarded_space(
 @param[in]	full		If true, do a full contraction based
 on PCT_IO(100). If false, the size of contract batch is determined
 based on the current size of the change buffer.
- at param[in]	space_id	tablespace for which to contract, or
-ULINT_UNDEFINED to contract for all tablespaces
 @return a lower limit for the combined size in bytes of entries which
 will be merged from ibuf trees to the pages read, 0 if ibuf is
 empty */
 ulint
 ibuf_merge_in_background(
-	bool	full,
-	ulint	space_id);
+	bool	full);
 
 /** Contracts insert buffer trees by reading pages referring to space_id
 to the buffer pool.
 @returns number of pages merged.*/
-UNIV_INTERN
 ulint
 ibuf_merge_space(
 /*=============*/
diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h
index 84050f3..eb554e0 100644
--- a/storage/innobase/include/lock0lock.h
+++ b/storage/innobase/include/lock0lock.h
@@ -285,7 +285,7 @@ lock_rec_insert_check_and_lock(
 				inserted record maybe should inherit
 				LOCK_GAP type locks from the successor
 				record */
-	MY_ATTRIBUTE((nonnull(2,3,4,6,7), warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*********************************************************************//**
 Enqueues a waiting request for a lock which cannot be granted immediately.
@@ -381,7 +381,7 @@ lock_clust_rec_modify_check_and_lock(
 	dict_index_t*		index,	/*!< in: clustered index */
 	const ulint*		offsets,/*!< in: rec_get_offsets(rec, index) */
 	que_thr_t*		thr)	/*!< in: query thread */
-	MY_ATTRIBUTE((warn_unused_result, nonnull));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Checks if locks of other transactions prevent an immediate modify
 (delete mark or delete unmark) of a secondary index record.
@@ -401,7 +401,7 @@ lock_sec_rec_modify_check_and_lock(
 	que_thr_t*	thr,	/*!< in: query thread
 				(can be NULL if BTR_NO_LOCKING_FLAG) */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
-	MY_ATTRIBUTE((warn_unused_result, nonnull(2,3,4,6)));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Like lock_clust_rec_read_check_and_lock(), but reads a
 secondary index record.
@@ -485,7 +485,7 @@ lock_clust_rec_read_check_and_lock_alt(
 	ulint			gap_mode,/*!< in: LOCK_ORDINARY, LOCK_GAP, or
 					LOCK_REC_NOT_GAP */
 	que_thr_t*		thr)	/*!< in: query thread */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Checks that a record is seen in a consistent read.
 @return true if sees, or false if an earlier version of the record
@@ -511,11 +511,12 @@ clustered index record might be needed */
 bool
 lock_sec_rec_cons_read_sees(
 /*========================*/
-	const rec_t*	rec,	/*!< in: user record which should be read or
-				passed over by a read cursor */
-	const dict_index_t*	index,	/*!< in: clustered index */
-	const ulint*	offsets,/*!< in: rec_get_offsets(rec, index) */
-	const ReadView*	view);	/*!< in: consistent read view */
+	const rec_t*		rec,	/*!< in: user record which
+					should be read or passed over
+					by a read cursor */
+	const dict_index_t*     index,  /*!< in: index */
+	const ReadView*	view)	/*!< in: consistent read view */
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Locks the specified database table in the mode given. If the lock cannot
 be granted immediately, the query thread is put to wait.
@@ -529,7 +530,7 @@ lock_table(
 				in dictionary cache */
 	lock_mode	mode,	/*!< in: lock mode */
 	que_thr_t*	thr)	/*!< in: query thread */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Creates a table IX lock object for a resurrected transaction. */
 void
@@ -537,6 +538,19 @@ lock_table_ix_resurrect(
 /*====================*/
 	dict_table_t*	table,	/*!< in/out: table */
 	trx_t*		trx);	/*!< in/out: transaction */
+
+/** Sets a lock on a table based on the given mode.
+ at param[in]	table	table to lock
+ at param[in,out]	trx	transaction
+ at param[in]	mode	LOCK_X or LOCK_S
+ at return error code or DB_SUCCESS. */
+dberr_t
+lock_table_for_trx(
+	dict_table_t*	table,
+	trx_t*		trx,
+	enum lock_mode	mode)
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
+
 /*************************************************************//**
 Removes a granted record lock of a transaction from the queue and grants
 locks to other transactions waiting in the queue if they now are entitled
@@ -634,8 +648,7 @@ ibool
 lock_is_table_exclusive(
 /*====================*/
 	const dict_table_t*	table,	/*!< in: table */
-	const trx_t*		trx)	/*!< in: transaction */
-	MY_ATTRIBUTE((nonnull));
+	const trx_t*		trx);	/*!< in: transaction */
 /*********************************************************************//**
 Checks if a lock request lock1 has to wait for request lock2.
 @return TRUE if lock1 has to wait for lock2 to be removed */
@@ -680,7 +693,7 @@ lock_print_info_summary(
 /*====================*/
 	FILE*	file,	/*!< in: file where to print */
 	ibool   nowait)	/*!< in: whether to wait for the lock mutex */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Prints transaction lock wait and MVCC state.
 @param[in,out]	file	file where to print
@@ -707,7 +720,7 @@ ulint
 lock_number_of_rows_locked(
 /*=======================*/
 	const trx_lock_t*	trx_lock)	/*!< in: transaction locks */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*********************************************************************//**
 Return the number of table locks for a transaction.
@@ -716,7 +729,7 @@ ulint
 lock_number_of_tables_locked(
 /*=========================*/
 	const trx_lock_t*	trx_lock)	/*!< in: transaction locks */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*******************************************************************//**
 Gets the type of a lock. Non-inline version for using outside of the
@@ -900,7 +913,7 @@ lock_check_trx_id_sanity(
 	const rec_t*	rec,		/*!< in: user record */
 	dict_index_t*	index,		/*!< in: index */
 	const ulint*	offsets)	/*!< in: rec_get_offsets(rec, index) */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /*******************************************************************//**
 Check if the transaction holds any locks on the sys tables
 or its records.
@@ -921,7 +934,7 @@ lock_trx_has_rec_x_lock(
 	const dict_table_t*	table,	/*!< in: table to check */
 	const buf_block_t*	block,	/*!< in: buffer block of the record */
 	ulint			heap_no)/*!< in: record heap number */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 #endif /* UNIV_DEBUG */
 
 /**
@@ -1141,6 +1154,7 @@ lock_update_split_and_merge(
 	const buf_block_t* right_block);/*!< in: right page from which merged */
 
 #endif /* WITH_WSREP */
+
 #ifndef UNIV_NONINL
 #include "lock0lock.ic"
 #endif
diff --git a/storage/innobase/include/lock0prdt.h b/storage/innobase/include/lock0prdt.h
index 8941a13..6c61f07 100644
--- a/storage/innobase/include/lock0prdt.h
+++ b/storage/innobase/include/lock0prdt.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, 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
@@ -203,22 +203,25 @@ lock_prdt_rec_move(
 	const buf_block_t*	donator);	/*!< in: buffer block containing
 						the donating record */
 
-/*********************************************************************//**
-Check whether there are R-tree Page lock on a buffer page
+/** Check whether there are R-tree Page lock on a buffer page
+ at param[in]	trx	trx to test the lock
+ at param[in]	space	space id for the page
+ at param[in]	page_no	page number
 @return true if there is none */
 bool
 lock_test_prdt_page_lock(
 /*=====================*/
-	ulint		space,		/*!< in: space id for the page */
-	ulint		page_no);	/*!< in: page number */
+	const trx_t*	trx,
+	ulint		space,
+	ulint		page_no);
 
-/*************************************************************//**
-Removes predicate lock objects set on an index page which is discarded. */
+/** Removes predicate lock objects set on an index page which is discarded.
+ at param[in]	block		page to be discarded
+ at param[in]	lock_hash	lock hash */
 void
-lock_prdt_free_from_discard_page(
+lock_prdt_page_free_from_discard(
 /*=============================*/
-	const buf_block_t*	block,	/*!< in: page to be discarded */
+	const buf_block_t*	block,
 	hash_table_t*		lock_hash);
-					/*!< in: lock hash */
 
 #endif
diff --git a/storage/innobase/include/lock0priv.h b/storage/innobase/include/lock0priv.h
index 06573d2..0b2ab1b 100644
--- a/storage/innobase/include/lock0priv.h
+++ b/storage/innobase/include/lock0priv.h
@@ -729,20 +729,23 @@ class RecLock {
 	Create a lock for a transaction and initialise it.
 	@param[in, out] trx		Transaction requesting the new lock
 	@param[in] owns_trx_mutex	true if caller owns the trx_t::mutex
+	@param[in] add_to_hash		add the lock to hash table
 	@param[in] prdt			Predicate lock (optional)
 	@return new lock instance */
 	lock_t* create(
 		trx_t*		trx,
 		bool		owns_trx_mutex,
+		bool		add_to_hash,
 		const lock_prdt_t*
 				prdt = NULL);
+
 	lock_t* create(
 		lock_t* const	c_lock,
 		trx_t*		trx,
 		bool		owns_trx_mutex,
+		bool		add_to_hash,
 		const lock_prdt_t*
 				prdt = NULL);
-
 	/**
 	Check of the lock is on m_rec_id.
 	@param[in] lock			Lock to compare with
@@ -765,19 +768,6 @@ class RecLock {
 		ulint		size);
 
 private:
-	/**
-	Enqueue a lock wait for a high priority transaction, jump the record
-	lock wait queue and if the transaction at the head of the queue is
-	itself waiting roll it back.
-	@param[in, out] wait_for	The lock that the joining
-					transaction is waiting for
-	@param[in] prdt			Predicate for the predicate lock
-	@return NULL if the lock was granted */
-	lock_t* enqueue_priority(
-		const lock_t*	wait_for,
-		const lock_prdt_t*
-				prdt);
-
 	/*
 	@return the record lock size in bytes */
 	size_t lock_size() const
@@ -795,15 +785,47 @@ class RecLock {
 	void mark_trx_for_rollback(trx_t* trx);
 
 	/**
-	Add the lock to the head of the record lock {space, page_no} wait
-	queue and the transaction's lock list. If the transactions holding
-	blocking locks are already marked for termination then they are not
-	added to the hit list.
-	@param[in, out] lock		Lock being requested
-	@param[in] wait_for		The blocking lock
-	@param[in] kill_trx		true if the transaction that m_trx
-					is waiting for should be killed */
-	void jump_queue(lock_t* lock, const lock_t* wait_for, bool kill_trx);
+	Jump the queue for the record over all low priority transactions and
+	add the lock. If all current granted locks are compatible, grant the
+	lock. Otherwise, mark all granted transaction for asynchronous
+	rollback and add to hit list.
+	@param[in, out]	lock		Lock being requested
+	@param[in]	conflict_lock	First conflicting lock from the head
+	@return true if the lock is granted */
+	bool jump_queue(lock_t* lock, const lock_t* conflict_lock);
+
+	/** Find position in lock queue and add the high priority transaction
+	lock. Intention and GAP only locks can be granted even if there are
+	waiting locks in front of the queue. To add the High priority
+	transaction in a safe position we keep the following rule.
+
+	1. If the lock can be granted, add it before the first waiting lock
+	in the queue so that all currently waiting locks need to do conflict
+	check before getting granted.
+
+	2. If the lock has to wait, add it after the last granted lock or the
+	last waiting high priority transaction in the queue whichever is later.
+	This ensures that the transaction is granted only after doing conflict
+	check with all granted transactions.
+	@param[in]      lock            Lock being requested
+	@param[in]      conflict_lock   First conflicting lock from the head
+	@param[out]     high_priority   high priority transaction ahead in queue
+	@return true if the lock can be granted */
+	bool
+	lock_add_priority(
+		lock_t*		lock,
+		const lock_t*	conflict_lock,
+		bool*		high_priority);
+
+	/** Iterate over the granted locks and prepare the hit list for ASYNC Rollback.
+	If the transaction is waiting for some other lock then wake up with deadlock error.
+	Currently we don't mark following transactions for ASYNC Rollback.
+	1. Read only transactions
+	2. Background transactions
+	3. Other High priority transactions
+	@param[in]      lock            Lock being requested
+	@param[in]      conflict_lock   First conflicting lock from the head */
+	void make_trx_hit_list(lock_t* lock, const lock_t* conflict_lock);
 
 	/**
 	Setup the requesting transaction state for lock grant
@@ -811,11 +833,6 @@ class RecLock {
 	void set_wait_state(lock_t* lock);
 
 	/**
-	Rollback the transaction that is blocking the requesting transaction
-	@param[in, out] lock	The blocking lock */
-	void rollback_blocking_trx(lock_t* lock) const;
-
-	/**
 	Add the lock to the record lock hash and the transaction's lock list
 	@param[in,out] lock	Newly created record lock to add to the
 				rec hash and the transaction lock list
@@ -987,7 +1004,7 @@ lock_clust_rec_some_has_impl(
 	const rec_t*		rec,	/*!< in: user record */
 	const dict_index_t*	index,	/*!< in: clustered index */
 	const ulint*		offsets)/*!< in: rec_get_offsets(rec, index) */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*********************************************************************//**
 Gets the first or next record lock on a page.
diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h
index e67eef4..c1f2570 100644
--- a/storage/innobase/include/log0log.h
+++ b/storage/innobase/include/log0log.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
 Copyright (c) 2009, Google Inc.
 
 Portions of this file contain modifications contributed and copyrighted by
@@ -39,11 +39,7 @@ Created 12/9/1995 Heikki Tuuri
 #include "sync0rw.h"
 #endif /* !UNIV_HOTBACKUP */
 #include "log0crypt.h"
-
-
-#define LSN_MAX			IB_UINT64_MAX
-
-#define LSN_PF			UINT64PF
+#include "log0types.h"
 
 /** Redo log buffer */
 struct log_t;
@@ -178,7 +174,7 @@ log_init(void);
 /******************************************************************//**
 Inits a log group to the log system.
 @return true if success, false if not */
-__attribute__((warn_unused_result))
+MY_ATTRIBUTE((warn_unused_result))
 bool
 log_group_init(
 /*===========*/
@@ -564,7 +560,9 @@ or the MySQL version that created the redo log file. */
 /** The redo log format identifier corresponding to the current format version.
 Stored in LOG_HEADER_FORMAT. */
 #define LOG_HEADER_FORMAT_CURRENT	1
-/* @} */
+
+// JAN: TODO: Shoud 32 here be LOG_HEADER_CREATOR_END ?
+// Problem: Log format 5.6 == 5.7 ?
 #define LOG_CHECKPOINT_ARRAY_END	(32 + 32 * 8)
 #define LOG_CRYPT_VER			(20 + LOG_CHECKPOINT_ARRAY_END)
 #define LOG_CRYPT_MAX_ENTRIES           (5)
@@ -575,6 +573,7 @@ Stored in LOG_HEADER_FORMAT. */
 
 #define LOG_CHECKPOINT_SIZE		(20 + LOG_CHECKPOINT_ARRAY_END + \
 					 LOG_CRYPT_SIZE)
+/* @} */
 
 #define LOG_CHECKPOINT_1	OS_FILE_LOG_BLOCK_SIZE
 					/* first checkpoint field in the log
@@ -600,7 +599,9 @@ typedef ib_mutex_t	FlushOrderMutex;
 
 /** Log group consists of a number of log files, each of the same size; a log
 group is implemented as a space in the sense of the module fil0fil.
-The fields are protected by log_sys->mutex. */
+Currently, this is only protected by log_sys->mutex. However, in the case
+of log_write_up_to(), we will access some members only with the protection
+of log_sys->write_mutex, which should affect nothing for now. */
 struct log_group_t{
 	/** log group identifier (always 0) */
 	ulint				id;
@@ -642,11 +643,14 @@ struct log_t{
 					same memory cache line */
 	lsn_t		lsn;		/*!< log sequence number */
 	ulint		buf_free;	/*!< first free offset within the log
-					buffer */
+					buffer in use */
 #ifndef UNIV_HOTBACKUP
 	char		pad2[CACHE_LINE_SIZE];/*!< Padding */
 	LogSysMutex	mutex;		/*!< mutex protecting the log */
-	char		pad3[CACHE_LINE_SIZE];/*!< Padding */
+	char		pad3[CACHE_LINE_SIZE]; /*!< Padding */
+	LogSysMutex	write_mutex;	/*!< mutex protecting writing to log
+					file and accessing to log_group_t */
+	char		pad4[CACHE_LINE_SIZE];/*!< Padding */
 	FlushOrderMutex	log_flush_order_mutex;/*!< mutex to serialize access to
 					the flush list when we are putting
 					dirty blocks in the list. The idea
@@ -656,12 +660,22 @@ struct log_t{
 					insertions in the flush_list happen
 					in the LSN order. */
 #endif /* !UNIV_HOTBACKUP */
-	byte*		buf_ptr;	/* unaligned log buffer */
-	byte*		buf;		/*!< log buffer */
-	ulint		buf_size;	/*!< log buffer size in bytes */
+	byte*		buf_ptr;	/*!< unaligned log buffer, which should
+					be of double of buf_size */
+	byte*		buf;		/*!< log buffer currently in use;
+					this could point to either the first
+					half of the aligned(buf_ptr) or the
+					second half in turns, so that log
+					write/flush to disk don't block
+					concurrent mtrs which will write
+					log to this buffer */
+	bool		first_in_use;	/*!< true if buf points to the first
+					half of the aligned(buf_ptr), false
+					if the second half */
+	ulint		buf_size;	/*!< log buffer size of each in bytes */
 	ulint		max_buf_free;	/*!< recommended maximum value of
-					buf_free, after which the buffer is
-					flushed */
+					buf_free for the buffer in use, after
+					which the buffer is flushed */
 	bool		check_flush_or_checkpoint;
 					/*!< this is set when there may
 					be need to flush the log buffer, or
@@ -687,11 +701,6 @@ struct log_t{
 	volatile bool	is_extending;	/*!< this is set to true during extend
 					the log buffer size */
 	lsn_t		write_lsn;	/*!< last written lsn */
-	ulint		write_end_offset;/*!< the data in buffer has
-					been written up to this offset
-					when the current write ends:
-					this field will then be copied
-					to buf_next_to_write */
 	lsn_t		current_flush_lsn;/*!< end lsn for the current running
 					write + flush operation */
 	lsn_t		flushed_to_disk_lsn;
@@ -786,12 +795,33 @@ struct log_t{
 /** Test if log sys mutex is owned. */
 #define log_mutex_own() mutex_own(&log_sys->mutex)
 
+/** Test if log sys write mutex is owned. */
+#define log_write_mutex_own() mutex_own(&log_sys->write_mutex)
+
 /** Acquire the log sys mutex. */
 #define log_mutex_enter() mutex_enter(&log_sys->mutex)
 
+/** Acquire the log sys write mutex. */
+#define log_write_mutex_enter() mutex_enter(&log_sys->write_mutex)
+
+/** Acquire all the log sys mutexes. */
+#define log_mutex_enter_all() do {		\
+	mutex_enter(&log_sys->write_mutex);	\
+	mutex_enter(&log_sys->mutex);		\
+} while (0)
+
 /** Release the log sys mutex. */
 #define log_mutex_exit() mutex_exit(&log_sys->mutex)
 
+/** Release the log sys write mutex.*/
+#define log_write_mutex_exit() mutex_exit(&log_sys->write_mutex)
+
+/** Release all the log sys mutexes. */
+#define log_mutex_exit_all() do {		\
+	mutex_exit(&log_sys->mutex);		\
+	mutex_exit(&log_sys->write_mutex);	\
+} while (0)
+
 /** Calculate the offset of an lsn within a log group.
 @param[in]	lsn	log sequence number
 @param[in]	group	log group
diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic
index caf4976..a53f877 100644
--- a/storage/innobase/include/log0log.ic
+++ b/storage/innobase/include/log0log.ic
@@ -439,15 +439,14 @@ Gets the last lsn that is fully flushed to disk.
 UNIV_INLINE
 ib_uint64_t
 log_get_flush_lsn(void)
-/*=============*/
 {
 	ib_uint64_t	lsn;
 
-	mutex_enter(&(log_sys->mutex));
+	log_mutex_enter();
 
 	lsn = log_sys->flushed_to_disk_lsn;
 
-	mutex_exit(&(log_sys->mutex));
+	log_mutex_exit();
 
 	return(lsn);
 }
@@ -458,7 +457,7 @@ Gets the current lsn with a trylock
 UNIV_INLINE
 lsn_t
 log_get_lsn_nowait(void)
-/*=============*/
+/*====================*/
 {
 	lsn_t	lsn=0;
 
diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h
index 85b326e..bd71186 100644
--- a/storage/innobase/include/log0recv.h
+++ b/storage/innobase/include/log0recv.h
@@ -35,6 +35,7 @@ Created 9/20/1997 Heikki Tuuri
 #include "ut0new.h"
 
 #include <list>
+#include <vector>
 
 #ifdef UNIV_HOTBACKUP
 extern bool	recv_replay_file_ops;
@@ -278,6 +279,16 @@ struct recv_dblwr_t {
 	list	pages;
 };
 
+/* Recovery encryption information */
+typedef	struct recv_encryption {
+	ulint		space_id;	/*!< the page number */
+	byte*		key;		/*!< encryption key */
+	byte*		iv;		/*!< encryption iv */
+} recv_encryption_t;
+
+typedef std::vector<recv_encryption_t, ut_allocator<recv_encryption_t> >
+		encryption_list_t;
+
 /** Recovery system data structure */
 struct recv_sys_t{
 #ifndef UNIV_HOTBACKUP
@@ -346,6 +357,9 @@ struct recv_sys_t{
 				addresses in the hash table */
 
 	recv_dblwr_t	dblwr;
+
+	encryption_list_t*	/*!< Encryption information list */
+			encryption_list;
 };
 
 /** The recovery system */
@@ -404,7 +418,7 @@ extern ulint	recv_n_pool_free_frames;
 /******************************************************//**
 Checks the 4-byte checksum to the trailer checksum field of a log
 block.  */
-ibool
+bool
 log_block_checksum_is_ok(
 /*===================================*/
 	const byte*	block,	/*!< in: pointer to a log block */
diff --git a/storage/innobase/include/mach0data.h b/storage/innobase/include/mach0data.h
index 07e2313..4d32e2e 100644
--- a/storage/innobase/include/mach0data.h
+++ b/storage/innobase/include/mach0data.h
@@ -53,7 +53,7 @@ ulint
 mach_read_from_1(
 /*=============*/
 	const byte*	b)	/*!< in: pointer to byte */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*******************************************************//**
 The following function is used to store data in two consecutive
 bytes. We store the most significant byte to the lower address. */
@@ -72,7 +72,7 @@ ulint
 mach_read_from_2(
 /*=============*/
 	const byte*	b)	/*!< in: pointer to two bytes */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /********************************************************//**
 The following function is used to convert a 16-bit data item
@@ -114,7 +114,7 @@ ulint
 mach_read_from_3(
 /*=============*/
 	const byte*	b)	/*!< in: pointer to 3 bytes */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*******************************************************//**
 The following function is used to store data in four consecutive
 bytes. We store the most significant byte to the lowest address. */
@@ -133,7 +133,7 @@ ulint
 mach_read_from_4(
 /*=============*/
 	const byte*	b)	/*!< in: pointer to four bytes */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************//**
 Writes a ulint in a compressed form (1..5 bytes).
 @return stored size in bytes */
@@ -159,8 +159,7 @@ advanced by the number of bytes consumed
 UNIV_INLINE
 ib_uint32_t
 mach_read_next_compressed(
-	const byte**	b)
-	MY_ATTRIBUTE((nonnull, pure));
+	const byte**	b);
 /*******************************************************//**
 The following function is used to store data in 6 consecutive
 bytes. We store the most significant byte to the lowest address. */
@@ -179,7 +178,7 @@ ib_uint64_t
 mach_read_from_6(
 /*=============*/
 	const byte*	b)	/*!< in: pointer to 6 bytes */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*******************************************************//**
 The following function is used to store data in 7 consecutive
 bytes. We store the most significant byte to the lowest address. */
@@ -198,7 +197,7 @@ ib_uint64_t
 mach_read_from_7(
 /*=============*/
 	const byte*	b)	/*!< in: pointer to 7 bytes */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*******************************************************//**
 The following function is used to store data in 8 consecutive
 bytes. We store the most significant byte to the lowest address. */
@@ -217,7 +216,7 @@ ib_uint64_t
 mach_read_from_8(
 /*=============*/
 	const byte*	b)	/*!< in: pointer to 8 bytes */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************//**
 Writes a 64-bit integer in a compressed form (5..9 bytes).
 @return size in bytes */
@@ -252,7 +251,7 @@ ib_uint64_t
 mach_u64_read_much_compressed(
 /*==========================*/
 	const byte*	b)	/*!< in: pointer to memory from where to read */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /** Read a 32-bit integer in a compressed form.
 @param[in,out]	ptr	pointer to memory where to read;
 advanced by the number of bytes consumed, or set NULL if out of space
@@ -281,7 +280,7 @@ double
 mach_double_read(
 /*=============*/
 	const byte*	b)	/*!< in: pointer to memory from where to read */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************//**
 Writes a double. It is stored in a little-endian format. */
 UNIV_INLINE
@@ -298,7 +297,7 @@ float
 mach_float_read(
 /*============*/
 	const byte*	b)	/*!< in: pointer to memory from where to read */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************//**
 Writes a float. It is stored in a little-endian format. */
 UNIV_INLINE
@@ -316,7 +315,7 @@ mach_read_from_n_little_endian(
 /*===========================*/
 	const byte*	buf,		/*!< in: from where to read */
 	ulint		buf_size)	/*!< in: from how many bytes to read */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************//**
 Writes a ulint in the little-endian format. */
 UNIV_INLINE
@@ -334,7 +333,7 @@ ulint
 mach_read_from_2_little_endian(
 /*===========================*/
 	const byte*	buf)		/*!< in: from where to read */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************//**
 Writes a ulint in the little-endian format. */
 UNIV_INLINE
@@ -387,7 +386,7 @@ ulint
 mach_read_ulint(
 	const byte*	ptr,
 	mlog_id_t	type)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 #endif /* !UNIV_HOTBACKUP */
 #endif /* !UNIV_INNOCHECKSUM */
diff --git a/storage/innobase/include/mach0data.ic b/storage/innobase/include/mach0data.ic
index 88c88cf..ece4a37 100644
--- a/storage/innobase/include/mach0data.ic
+++ b/storage/innobase/include/mach0data.ic
@@ -42,6 +42,7 @@ mach_write_to_1(
 
 	b[0] = (byte) n;
 }
+
 #endif /* !UNIV_INNOCHECKSUM */
 
 /*******************************************************//**
@@ -948,4 +949,3 @@ mach_read_ulint(
 
 #endif /* !UNIV_HOTBACKUP */
 #endif /* !UNIV_INNOCHECKSUM */
-
diff --git a/storage/innobase/include/mem0mem.h b/storage/innobase/include/mem0mem.h
index 72791e2..f8fdb53 100644
--- a/storage/innobase/include/mem0mem.h
+++ b/storage/innobase/include/mem0mem.h
@@ -207,7 +207,7 @@ mem_heap_is_top(
 	mem_heap_t*	heap,
 	const void*	buf,
 	ulint		buf_sz)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*****************************************************************//**
 Allocate a new chunk of memory from a memory heap, possibly discarding
diff --git a/storage/innobase/include/mem0mem.ic b/storage/innobase/include/mem0mem.ic
index d20a164..3b4109e 100644
--- a/storage/innobase/include/mem0mem.ic
+++ b/storage/innobase/include/mem0mem.ic
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2014, 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/mtr0log.ic b/storage/innobase/include/mtr0log.ic
index 07aa08e..4015fe3 100644
--- a/storage/innobase/include/mtr0log.ic
+++ b/storage/innobase/include/mtr0log.ic
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, 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
@@ -214,11 +214,8 @@ mlog_write_initial_log_record_fast(
 	ulint		space;
 	ulint		offset;
 
-	ut_ad(mtr->memo_contains_page_flagged(
-			ptr,
-			MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX));
-
-	ut_ad(ptr && log_ptr);
+	ut_ad(log_ptr);
+	ut_d(mtr->memo_modify_page(ptr));
 
 	page = (const byte*) ut_align_down(ptr, UNIV_PAGE_SIZE);
 	space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
@@ -247,18 +244,7 @@ mlog_write_initial_log_record_fast(
 		}
 	}
 
-	log_ptr = mlog_write_initial_log_record_low(
-		type, space, offset, log_ptr, mtr);
-
-#ifdef UNIV_DEBUG
-	/* We now assume that all x-latched pages have been modified! */
-	buf_block_t*	block = (buf_block_t*) buf_block_align(ptr);
-
-	if (!mtr->memo_contains(mtr->get_memo(), block, MTR_MEMO_MODIFY)) {
-		mtr->memo_push(block, MTR_MEMO_MODIFY);
-	}
-#endif /* UNIV_DEBUG */
-
-	return(log_ptr);
+	return(mlog_write_initial_log_record_low(type, space, offset,
+						 log_ptr, mtr));
 }
 #endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h
index d3aa191..4a1d867 100644
--- a/storage/innobase/include/mtr0mtr.h
+++ b/storage/innobase/include/mtr0mtr.h
@@ -37,7 +37,6 @@ Created 11/26/1995 Heikki Tuuri
 
 /** Start a mini-transaction. */
 #define mtr_start(m)		(m)->start()
-
 /** Start a mini-transaction. */
 #define mtr_start_trx(m, t)		(m)->start((t))
 
@@ -105,8 +104,7 @@ savepoint. */
 /** Check if memo contains the given page.
 @return	TRUE if contains */
 #define mtr_memo_contains_page(m, p, t)					\
-				(m)->memo_contains_page(		\
-					(m)->get_memo(), (p), (t))
+	(m)->memo_contains_page_flagged((p), (t))
 #endif /* UNIV_DEBUG */
 
 /** Print info of an mtr handle. */
@@ -280,7 +278,7 @@ struct mtr_t {
 	/** Return current size of the buffer.
 	@return	savepoint */
 	ulint get_savepoint() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		ut_ad(is_active());
 		ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
@@ -310,7 +308,7 @@ struct mtr_t {
 	/** Get the logging mode.
 	@return	logging mode */
 	inline mtr_log_t get_log_mode() const
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Change the logging mode.
 	@param mode	 logging mode
@@ -379,7 +377,7 @@ struct mtr_t {
 	@param type)	MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES
 	@return	value read */
 	inline ulint read_ulint(const byte* ptr, mlog_id_t type) const
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Locks a rw-latch in S mode.
 	NOTE: use mtr_s_lock().
@@ -418,6 +416,10 @@ struct mtr_t {
 	@param type	object type: MTR_MEMO_S_LOCK, ...
 	@return bool if lock released */
 	bool memo_release(const void* object, ulint type);
+	/** Release a page latch.
+	@param[in]	ptr	pointer to within a page frame
+	@param[in]	type	object type: MTR_MEMO_PAGE_X_FIX, ... */
+	void release_page(const void* ptr, mtr_memo_type_t type);
 
 	/** Note that the mini-transaction has modified data. */
 	void set_modified()
@@ -494,18 +496,7 @@ struct mtr_t {
 		mtr_buf_t*	memo,
 		const void*	object,
 		ulint		type)
-		__attribute__((warn_unused_result));
-
-	/** Check if memo contains the given page.
-	@param memo	memo stack
-	@param ptr	pointer to buffer frame
-	@param type	type of object
-	@return	true if contains */
-	static bool memo_contains_page(
-		mtr_buf_t*	memo,
-		const byte*	ptr,
-		ulint		type)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Check if memo contains the given item.
 	@param object		object to search
@@ -515,11 +506,18 @@ struct mtr_t {
 	bool memo_contains_flagged(const void* ptr, ulint flags) const;
 
 	/** Check if memo contains the given page.
-	@param ptr		buffer frame
-	@param flags		specify types of object with OR of
+	@param[in]	ptr	pointer to within buffer frame
+	@param[in]	flags	specify types of object with OR of
 				MTR_MEMO_PAGE_S_FIX... values
-	@return true if contains */
-	bool memo_contains_page_flagged(const byte* ptr, ulint flags) const;
+	@return	the block
+	@retval	NULL	if not found */
+	buf_block_t* memo_contains_page_flagged(
+		const byte*	ptr,
+		ulint		flags) const;
+
+	/** Mark the given latched page as modified.
+	@param[in]	ptr	pointer to within buffer frame */
+	void memo_modify_page(const byte* ptr);
 
 	/** Print info of an mtr handle. */
 	void print() const;
@@ -594,7 +592,7 @@ struct mtr_t {
 	@param block	block being x-fixed
 	@return true if the mtr is dirtying a clean page. */
 	static bool is_block_dirtied(const buf_block_t* block)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 private:
 	/** Look up the system tablespace. */
diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic
index 6c61f8d..b3d9b05 100644
--- a/storage/innobase/include/mtr0mtr.ic
+++ b/storage/innobase/include/mtr0mtr.ic
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2014, 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/os0atomic.h b/storage/innobase/include/os0atomic.h
index 1368176..8e2b06b 100644
--- a/storage/innobase/include/os0atomic.h
+++ b/storage/innobase/include/os0atomic.h
@@ -1,5 +1,5 @@
 /*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
 Copyright (c) 2008, Google Inc.
 
 Portions of this file contain modifications contributed and copyrighted by
@@ -208,6 +208,8 @@ amount to decrement. There is no atomic substract function on Windows */
 Returns true if swapped, ptr is pointer to target, old_val is value to
 compare to, new_val is the value to swap in. */
 
+#if defined(HAVE_GCC_SYNC_BUILTINS)
+
 # define os_compare_and_swap(ptr, old_val, new_val) \
 	__sync_bool_compare_and_swap(ptr, old_val, new_val)
 
@@ -220,9 +222,47 @@ compare to, new_val is the value to swap in. */
 # define os_compare_and_swap_uint32(ptr, old_val, new_val) \
 	os_compare_and_swap(ptr, old_val, new_val)
 
+#else
+
+UNIV_INLINE
+bool
+os_compare_and_swap_ulint(volatile ulint* ptr, ulint old_val, ulint new_val)
+{
+  return __atomic_compare_exchange_n(ptr, &old_val, new_val, 0,
+                                     __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+UNIV_INLINE
+bool
+os_compare_and_swap_lint(volatile lint* ptr, lint old_val, lint new_val)
+{
+  return __atomic_compare_exchange_n(ptr, &old_val, new_val, 0,
+				     __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+UNIV_INLINE
+bool
+os_compare_and_swap_uint32(volatile ib_uint32_t* ptr, ib_uint32_t old_val, ib_uint32_t new_val)
+{
+  return __atomic_compare_exchange_n(ptr, &old_val, new_val, 0,
+                                     __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+#endif /* HAVE_GCC_SYNC_BUILTINS */
+
 # ifdef HAVE_IB_ATOMIC_PTHREAD_T_GCC
+#if defined(HAVE_GCC_SYNC_BUILTINS)
 #  define os_compare_and_swap_thread_id(ptr, old_val, new_val) \
 	os_compare_and_swap(ptr, old_val, new_val)
+#else
+UNIV_INLINE
+bool
+os_compare_and_swap_thread_id(volatile os_thread_id_t* ptr, os_thread_id_t old_val, os_thread_id_t new_val)
+{
+  return __atomic_compare_exchange_n(ptr, &old_val, new_val, 0,
+                                     __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+#endif /* HAVE_GCC_SYNC_BUILTINS */
 #  define INNODB_RW_LOCKS_USE_ATOMICS
 #  define IB_ATOMICS_STARTUP_MSG \
 	"Mutexes and rw_locks use GCC atomic builtins"
@@ -235,8 +275,13 @@ compare to, new_val is the value to swap in. */
 Returns the resulting value, ptr is pointer to target, amount is the
 amount of increment. */
 
+#if defined(HAVE_GCC_SYNC_BUILTINS)
 # define os_atomic_increment(ptr, amount) \
 	__sync_add_and_fetch(ptr, amount)
+#else
+# define os_atomic_increment(ptr, amount) \
+	__atomic_add_fetch(ptr, amount, __ATOMIC_SEQ_CST)
+#endif /* HAVE_GCC_SYNC_BUILTINS */
 
 # define os_atomic_increment_lint(ptr, amount) \
 	os_atomic_increment(ptr, amount)
@@ -253,8 +298,13 @@ amount of increment. */
 /* Returns the resulting value, ptr is pointer to target, amount is the
 amount to decrement. */
 
+#if defined(HAVE_GCC_SYNC_BUILTINS)
 # define os_atomic_decrement(ptr, amount) \
 	__sync_sub_and_fetch(ptr, amount)
+#else
+# define os_atomic_decrement(ptr, amount) \
+	__atomic_sub_fetch(ptr, amount, __ATOMIC_SEQ_CST)
+#endif /* HAVE_GCC_SYNC_BUILTINS */
 
 # define os_atomic_decrement_lint(ptr, amount) \
 	os_atomic_decrement(ptr, amount)
diff --git a/storage/innobase/include/os0atomic.ic b/storage/innobase/include/os0atomic.ic
index 651f7b5..1f1c460 100644
--- a/storage/innobase/include/os0atomic.ic
+++ b/storage/innobase/include/os0atomic.ic
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, 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
@@ -152,7 +152,11 @@ os_atomic_test_and_set(
 	/* Silence a compiler warning about unused ptr. */
 	(void) ptr;
 
+#if defined(__powerpc__) || defined(__aarch64__)
+	__atomic_exchange(ptr, &new_val,  &ret, __ATOMIC_SEQ_CST);
+#else
 	__atomic_exchange(ptr, &new_val,  &ret, __ATOMIC_RELEASE);
+#endif
 
 	return(ret);
 }
@@ -172,8 +176,13 @@ os_atomic_val_compare_and_swap(
 	/* Silence a compiler warning about unused ptr. */
 	(void) ptr;
 
+#if defined(__powerpc__) || defined(__aarch64__)
+	__atomic_compare_exchange(ptr, &old_val, &new_val, false,
+				  __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+#else
 	__atomic_compare_exchange(ptr, &old_val, &new_val, false,
 				  __ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
+#endif
 
 	return(old_val);
 }
diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h
index 5aa1843..5e36cfc 100644
--- a/storage/innobase/include/os0file.h
+++ b/storage/innobase/include/os0file.h
@@ -137,6 +137,7 @@ static const ulint OS_FILE_READ_WRITE = 444;
 
 /** Used by MySQLBackup */
 static const ulint OS_FILE_READ_ALLOW_DELETE = 555;
+
 /* Options for file_create */
 static const ulint OS_FILE_AIO = 61;
 static const ulint OS_FILE_NORMAL = 62;
@@ -154,6 +155,7 @@ static const ulint OS_FILE_NOT_FOUND = 71;
 static const ulint OS_FILE_DISK_FULL = 72;
 static const ulint OS_FILE_ALREADY_EXISTS = 73;
 static const ulint OS_FILE_PATH_ERROR = 74;
+
 /** wait for OS aio resources to become available again */
 static const ulint OS_FILE_AIO_RESOURCES_RESERVED = 75;
 
@@ -230,32 +232,32 @@ struct Compression {
 	@param[in]	page		Page contents
 	@return true if it is a compressed page */
 	static bool is_compressed_page(const byte* page)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
         /** Check wether the compression algorithm is supported.
         @param[in]      algorithm       Compression algorithm to check
         @param[out]     type            The type that algorithm maps to
         @return DB_SUCCESS or error code */
 	static dberr_t check(const char* algorithm, Compression* type)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
         /** Validate the algorithm string.
         @param[in]      algorithm       Compression algorithm to check
         @return DB_SUCCESS or error code */
 	static dberr_t validate(const char* algorithm)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
         /** Convert to a "string".
         @param[in]      type            The compression type
         @return the string representation */
         static const char* to_string(Type type)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
         /** Convert the meta data to a std::string.
         @param[in]      meta		Page Meta data
         @return the string representation */
         static std::string to_string(const meta_t& meta)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Deserizlise the page header compression meta-data
 	@param[in]	header		Pointer to the page header
@@ -268,7 +270,7 @@ struct Compression {
         @param[in]      algorithm       Compression algorithm to check
         @return true if no algorithm requested */
 	static bool is_none(const char* algorithm)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Decompress the page data contents. Page type must be
 	FIL_PAGE_COMPRESSED, if not then the source contents are
@@ -285,12 +287,215 @@ struct Compression {
 		byte*		src,
 		byte*		dst,
 		ulint		dst_len)
-		__attribute__((warn_unused_result));
+		MY_ATTRIBUTE((warn_unused_result));
 
 	/** Compression type */
 	Type		m_type;
 };
 
+/** Encryption key length */
+static const ulint ENCRYPTION_KEY_LEN = 32;
+
+/** Encryption magic bytes size */
+static const ulint ENCRYPTION_MAGIC_SIZE = 3;
+
+/** Encryption magic bytes for 5.7.11, it's for checking the encryption information
+version. */
+static const char ENCRYPTION_KEY_MAGIC_V1[] = "lCA";
+
+/** Encryption magic bytes for 5.7.12+, it's for checking the encryption information
+version. */
+static const char ENCRYPTION_KEY_MAGIC_V2[] = "lCB";
+
+/** Encryption master key prifix */
+static const char ENCRYPTION_MASTER_KEY_PRIFIX[] = "INNODBKey";
+
+/** Encryption master key prifix size */
+static const ulint ENCRYPTION_MASTER_KEY_PRIFIX_LEN = 9;
+
+/** Encryption master key prifix size */
+static const ulint ENCRYPTION_MASTER_KEY_NAME_MAX_LEN = 100;
+
+/** UUID of server instance, it's needed for composing master key name */
+static const ulint ENCRYPTION_SERVER_UUID_LEN = 36;
+
+/** Encryption information total size for 5.7.11: magic number + master_key_id +
+key + iv + checksum */
+static const ulint ENCRYPTION_INFO_SIZE_V1 = (ENCRYPTION_MAGIC_SIZE \
+					 + (ENCRYPTION_KEY_LEN * 2) \
+					 + 2 * sizeof(ulint));
+
+/** Encryption information total size: magic number + master_key_id +
+key + iv + server_uuid + checksum */
+static const ulint ENCRYPTION_INFO_SIZE_V2 = (ENCRYPTION_MAGIC_SIZE \
+					 + (ENCRYPTION_KEY_LEN * 2) \
+					 + ENCRYPTION_SERVER_UUID_LEN \
+					 + 2 * sizeof(ulint));
+
+class IORequest;
+
+/** Encryption algorithm. */
+struct Encryption {
+
+	/** Algorithm types supported */
+	enum Type {
+
+		/** No encryption */
+		NONE = 0,
+
+		/** Use AES */
+		AES = 1,
+	};
+
+	/** Encryption information format version */
+	enum Version {
+
+		/** Version in 5.7.11 */
+		ENCRYPTION_VERSION_1 = 0,
+
+		/** Version in > 5.7.11 */
+		ENCRYPTION_VERSION_2 = 1,
+	};
+
+	/** Default constructor */
+	Encryption() : m_type(NONE) { };
+
+	/** Specific constructor
+	@param[in]	type		Algorithm type */
+	explicit Encryption(Type type)
+		:
+		m_type(type)
+	{
+#ifdef UNIV_DEBUG
+		switch (m_type) {
+		case NONE:
+		case AES:
+
+		default:
+			ut_error;
+		}
+#endif /* UNIV_DEBUG */
+	}
+
+	/** Copy constructor */
+	Encryption(const Encryption& other)
+		:
+		m_type(other.m_type),
+		m_key(other.m_key),
+		m_klen(other.m_klen),
+		m_iv(other.m_iv)
+	{ };
+
+	/** Check if page is encrypted page or not
+	@param[in]	page	page which need to check
+	@return true if it is a encrypted page */
+	static bool is_encrypted_page(const byte* page)
+		MY_ATTRIBUTE((warn_unused_result));
+
+	/** Check the encryption option and set it
+	@param[in]	option		encryption option
+	@param[in/out]	encryption	The encryption type
+	@return DB_SUCCESS or DB_UNSUPPORTED */
+	dberr_t set_algorithm(const char* option, Encryption* type)
+		MY_ATTRIBUTE((warn_unused_result));
+
+        /** Validate the algorithm string.
+        @param[in]      algorithm       Encryption algorithm to check
+        @return DB_SUCCESS or error code */
+	static dberr_t validate(const char* algorithm)
+		MY_ATTRIBUTE((warn_unused_result));
+
+        /** Convert to a "string".
+        @param[in]      type            The encryption type
+        @return the string representation */
+        static const char* to_string(Type type)
+		MY_ATTRIBUTE((warn_unused_result));
+
+        /** Check if the string is "empty" or "none".
+        @param[in]      algorithm       Encryption algorithm to check
+        @return true if no algorithm requested */
+	static bool is_none(const char* algorithm)
+		MY_ATTRIBUTE((warn_unused_result));
+
+        /** Generate random encryption value for key and iv.
+        @param[in,out]	value	Encryption value */
+	static void random_value(byte* value);
+
+	/** Create new master key for key rotation.
+        @param[in,out]	master_key	master key */
+	static void create_master_key(byte** master_key);
+
+        /** Get master key by key id.
+        @param[in]	master_key_id	master key id
+	@param[in]	srv_uuid	uuid of server instance
+        @param[in,out]	master_key	master key */
+	static void get_master_key(ulint master_key_id,
+				   char* srv_uuid,
+				   byte** master_key);
+
+        /** Get current master key and key id.
+        @param[in,out]	master_key_id	master key id
+        @param[in,out]	master_key	master key
+        @param[in,out]	version		encryption information version */
+	static void get_master_key(ulint* master_key_id,
+				   byte** master_key,
+				   Encryption::Version*  version);
+
+	/** Encrypt the page data contents. Page type can't be
+	FIL_PAGE_ENCRYPTED, FIL_PAGE_COMPRESSED_AND_ENCRYPTED,
+	FIL_PAGE_ENCRYPTED_RTREE.
+	@param[in]	type		IORequest
+	@param[in,out]	src		page data which need to encrypt
+	@param[in]	src_len		Size of the source in bytes
+	@param[in,out]	dst		destination area
+	@param[in,out]	dst_len		Size of the destination in bytes
+	@return buffer data, dst_len will have the length of the data */
+	byte* encrypt(
+		const IORequest&	type,
+		byte*			src,
+		ulint			src_len,
+		byte*			dst,
+		ulint*			dst_len)
+		MY_ATTRIBUTE((warn_unused_result));
+
+	/** Decrypt the page data contents. Page type must be
+	FIL_PAGE_ENCRYPTED, FIL_PAGE_COMPRESSED_AND_ENCRYPTED,
+	FIL_PAGE_ENCRYPTED_RTREE, if not then the source contents are
+	left unchanged and DB_SUCCESS is returned.
+	@param[in]	type		IORequest
+	@param[in,out]	src		Data read from disk, decrypt
+					data will be copied to this page
+	@param[in]	src_len		source data length
+	@param[in,out]	dst		Scratch area to use for decrypt
+	@param[in]	dst_len		Size of the scratch area in bytes
+	@return DB_SUCCESS or error code */
+	dberr_t decrypt(
+		const IORequest&	type,
+		byte*			src,
+		ulint			src_len,
+		byte*			dst,
+		ulint			dst_len)
+		MY_ATTRIBUTE((warn_unused_result));
+
+	/** Encrypt type */
+	Type			m_type;
+
+	/** Encrypt key */
+	byte*			m_key;
+
+	/** Encrypt key length*/
+	ulint			m_klen;
+
+	/** Encrypt initial vector */
+	byte*			m_iv;
+
+	/** Current master key id */
+	static ulint		master_key_id;
+
+	/** Current uuid of server instance */
+	static char		uuid[ENCRYPTION_SERVER_UUID_LEN + 1];
+};
+
 /** Types for AIO operations @{ */
 
 /** No transformations during read/write, write as is. */
@@ -379,42 +584,42 @@ class IORequest {
 
 	/** @return true if ignore missing flag is set */
 	static bool ignore_missing(ulint type)
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return((type & IGNORE_MISSING) == IGNORE_MISSING);
 	}
 
 	/** @return true if it is a read request */
 	bool is_read() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return((m_type & READ) == READ);
 	}
 
 	/** @return true if it is a write request */
 	bool is_write() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return((m_type & WRITE) == WRITE);
 	}
 
 	/** @return true if it is a redo log write */
 	bool is_log() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return((m_type & LOG) == LOG);
 	}
 
 	/** @return true if the simulated AIO thread should be woken up */
 	bool is_wake() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return((m_type & DO_NOT_WAKE) == 0);
 	}
 
 	/** @return true if partial read warning disabled */
 	bool is_partial_io_warning_disabled() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return((m_type & DISABLE_PARTIAL_IO_WARNINGS)
 		       == DISABLE_PARTIAL_IO_WARNINGS);
@@ -428,21 +633,21 @@ class IORequest {
 
 	/** @return true if missing files should be ignored */
 	bool ignore_missing() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return(ignore_missing(m_type));
 	}
 
 	/** @return true if punch hole should be used */
 	bool punch_hole() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return((m_type & PUNCH_HOLE) == PUNCH_HOLE);
 	}
 
 	/** @return true if the read should be validated */
 	bool validate() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		ut_a(is_read() ^ is_write());
 
@@ -471,7 +676,7 @@ class IORequest {
 
 	/** @return the block size to use for IO */
 	ulint block_size() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return(m_block_size);
 	}
@@ -514,21 +719,21 @@ class IORequest {
 	/** Get the compression algorithm.
 	@return the compression algorithm */
 	Compression compression_algorithm() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return(m_compression);
 	}
 
 	/** @return true if the page should be compressed */
 	bool is_compressed() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return(compression_algorithm().m_type != Compression::NONE);
 	}
 
 	/** @return true if the page read should not be transformed. */
 	bool is_compression_enabled() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return((m_type & NO_COMPRESSION) == 0);
 	}
@@ -539,6 +744,54 @@ class IORequest {
 		m_type |= NO_COMPRESSION;
 	}
 
+	/** Set encryption algorithm
+	@param[in] type		The encryption algorithm to use */
+	void encryption_algorithm(Encryption::Type type)
+	{
+		if (type == Encryption::NONE) {
+			return;
+		}
+
+		m_encryption.m_type = type;
+	}
+
+	/** Set encryption key and iv
+	@param[in] key		The encryption key to use
+	@param[in] key_len	length of the encryption key
+	@param[in] iv		The encryption iv to use */
+	void encryption_key(byte* key,
+			    ulint key_len,
+			    byte* iv)
+	{
+		m_encryption.m_key = key;
+		m_encryption.m_klen = key_len;
+		m_encryption.m_iv = iv;
+	}
+
+	/** Get the encryption algorithm.
+	@return the encryption algorithm */
+	Encryption encryption_algorithm() const
+		MY_ATTRIBUTE((warn_unused_result))
+	{
+		return(m_encryption);
+	}
+
+	/** @return true if the page should be encrypted. */
+	bool is_encrypted() const
+		MY_ATTRIBUTE((warn_unused_result))
+	{
+		return(m_encryption.m_type != Encryption::NONE);
+	}
+
+	/** Clear all encryption related flags */
+	void clear_encrypted()
+	{
+		m_encryption.m_key = NULL;
+		m_encryption.m_klen = 0;
+		m_encryption.m_iv = NULL;
+		m_encryption.m_type = Encryption::NONE;
+	}
+
 	/** Note that the IO is for double write recovery. */
 	void dblwr_recover()
 	{
@@ -547,7 +800,7 @@ class IORequest {
 
 	/** @return true if the request is from the dblwr recovery */
 	bool is_dblwr_recover() const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		return((m_type & DBLWR_RECOVER) == DBLWR_RECOVER);
 	}
@@ -555,6 +808,14 @@ class IORequest {
 	/** @return true if punch hole is supported */
 	static bool is_punch_hole_supported()
 	{
+
+		/* In this debugging mode, we act as if punch hole is supported,
+		and then skip any calls to actually punch a hole here.
+		In this way, Transparent Page Compression is still being tested. */
+		DBUG_EXECUTE_IF("ignore_punch_hole",
+			return(true);
+		);
+
 #if defined(HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE) || defined(_WIN32)
 		return(true);
 #else
@@ -571,6 +832,9 @@ class IORequest {
 
 	/** Compression algorithm */
 	Compression		m_compression;
+
+	/** Encryption algorithm */
+	Encryption		m_encryption;
 };
 
 /* @} */
@@ -626,13 +890,13 @@ enum os_file_type_t {
 of this size from the thread stack; that is why this should not be made much
 bigger than 4000 bytes.  The maximum path length used by any storage engine
 in the server must be at least this big. */
-#define OS_FILE_MAX_PATH	4000
 
 /* MySQL 5.7 my_global.h */
 #ifndef FN_REFLEN_SE
 #define FN_REFLEN_SE        4000
 #endif
 
+#define OS_FILE_MAX_PATH	4000
 #if (FN_REFLEN_SE < OS_FILE_MAX_PATH)
 # error "(FN_REFLEN_SE < OS_FILE_MAX_PATH)"
 #endif
@@ -661,10 +925,9 @@ is null then it will create the file in the mysql server configuration
 parameter (--tmpdir).
 @param[in]	path	location for creating temporary file
 @return temporary file handle, or NULL on error */
-UNIV_INTERN
 FILE*
-os_file_create_tmpfile();
-
+os_file_create_tmpfile(
+	const char*	path);
 #endif /* !UNIV_HOTBACKUP */
 
 /** The os_file_opendir() function opens a directory stream corresponding to the
@@ -757,7 +1020,7 @@ os_file_create_simple_no_error_handling_func(
 	ulint		access_type,
 	bool		read_only,
 	bool*		success)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Tries to disable OS caching on an opened file descriptor.
 @param[in]	fd		file descriptor to alter
@@ -796,7 +1059,7 @@ os_file_create_func(
 	ulint		type,
 	bool		read_only,
 	bool*		success)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Deletes a file. The file has to be closed before calling this.
 @param[in]	name		file path as a null-terminated string
@@ -991,7 +1254,7 @@ pfs_os_file_create_simple_func(
 	bool*		success,
 	const char*	src_file,
 	ulint		src_line)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** NOTE! Please use the corresponding macro
 os_file_create_simple_no_error_handling(), not directly this function!
@@ -1022,7 +1285,7 @@ pfs_os_file_create_simple_no_error_handling_func(
 	bool*		success,
 	const char*	src_file,
 	ulint		src_line)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** NOTE! Please use the corresponding macro os_file_create(), not directly
 this function!
@@ -1051,12 +1314,12 @@ pfs_os_file_create_func(
 	const char*	name,
 	ulint		create_mode,
 	ulint		purpose,
-	ulint		access_type,
+	ulint		type,
 	bool		read_only,
 	bool*		success,
 	const char*	src_file,
 	ulint		src_line)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** NOTE! Please use the corresponding macro os_file_close(), not directly
 this function!
@@ -1266,7 +1529,7 @@ to original un-instrumented file I/O APIs */
 # define os_file_create(key, name, create, purpose, type, read_only,	\
 			success)					\
 	os_file_create_func(name, create, purpose, type, read_only,	\
-		success)
+			success)
 
 # define os_file_create_simple(key, name, create_mode, access,		\
 		read_only, success)					\
@@ -1321,7 +1584,7 @@ os_file_close_no_error_handling(os_file_t file);
 os_file_size_t
 os_file_get_size(
 	const char*	filename)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Gets a file size.
 @param[in]	file		handle to a file
@@ -1344,7 +1607,7 @@ os_file_set_size(
 	os_file_t	file,
 	os_offset_t	size,
 	bool		read_only)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Truncates a file at its current position.
 @param[in/out]	file	file to be truncated
@@ -1401,7 +1664,7 @@ os_file_read_func(
 	void*		buf,
 	os_offset_t	offset,
 	ulint		n)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Rewind file to its start, read at most size - 1 bytes from it to str, and
 NUL-terminate str. All errors are silently ignored. This function is
@@ -1434,7 +1697,7 @@ os_file_read_no_error_handling_func(
 	os_offset_t	offset,
 	ulint		n,
 	ulint*		o)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** NOTE! Use the corresponding macro os_file_write(), not directly this
 function!
@@ -1453,7 +1716,7 @@ os_file_write_func(
 	const void*	buf,
 	os_offset_t	offset,
 	ulint		n)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Check the existence and type of the given file.
 @param[in]	path		pathname of the file
@@ -1652,11 +1915,14 @@ os_file_get_status(
 	bool		read_only);
 
 #if !defined(UNIV_HOTBACKUP)
-/** Creates a temporary file that will be deleted on close.
+/** Creates a temporary file in the location specified by the parameter
+path. If the path is NULL then it will be created on --tmpdir location.
+This function is defined in ha_innodb.cc.
 @param[in]	path	location for creating temporary file
 @return temporary file descriptor, or < 0 on error */
 int
-innobase_mysql_tmpfile();
+innobase_mysql_tmpfile(
+	const char*	path);
 #endif /* !UNIV_HOTBACKUP */
 
 
@@ -1689,7 +1955,7 @@ os_file_punch_hole(
 	os_file_t	fh,
 	os_offset_t	off,
 	os_offset_t	len)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Check if the file system supports sparse files.
 
@@ -1706,7 +1972,7 @@ bool
 os_is_sparse_file_supported(
 	const char*	path,
 	os_file_t	fh)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Decompress the page data contents. Page type must be FIL_PAGE_COMPRESSED, if
 not then the source contents are left unchanged and DB_SUCCESS is returned.
@@ -1723,21 +1989,13 @@ os_file_decompress_page(
 	byte*		src,
 	byte*		dst,
 	ulint		dst_len)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Normalizes a directory path for the current OS:
 On Windows, we convert '/' to '\', else we convert '\' to '/'.
 @param[in,out] str A null-terminated directory and file path */
 void os_normalize_path(char*	str);
 
-/** Normalizes a directory path for Windows: converts '/' to '\'.
- at param[in,out] str A null-terminated Windows directory and file path */
-#ifdef _WIN32
-#define os_normalize_path_for_win(str)	os_normalize_path(str)
-#else
-#define os_normalize_path_for_win(str)
-#endif
-
 /* Determine if a path is an absolute path or not.
 @param[in]	OS directory or file path to evaluate
 @retval true if an absolute path
diff --git a/storage/innobase/include/os0file.ic b/storage/innobase/include/os0file.ic
index ec90548..74d0b2c 100644
--- a/storage/innobase/include/os0file.ic
+++ b/storage/innobase/include/os0file.ic
@@ -219,6 +219,11 @@ an asynchronous i/o operation.
 @param[in,out]	m2		message for the AIO handler (can be used to
 				identify a completed AIO operation); ignored
 				if mode is OS_AIO_SYNC
+ at param[in,out]	write_size	Actual write size initialized
+				after fist successfull trim
+				operation for this page and if
+				initialized we do not trim again if
+				actual page size 
 @param[in]	src_file	file name where func invoked
 @param[in]	src_line	line where the func invoked
 @return DB_SUCCESS if request was queued successfully, FALSE if fail */
@@ -235,11 +240,7 @@ pfs_os_aio_func(
 	bool		read_only,
 	fil_node_t*	m1,
 	void*		m2,
-	ulint*		write_size,/*!< in/out: Actual write size initialized
-			       after fist successfull trim
-			       operation for this page and if
-			       initialized we do not trim again if
-			       actual page size does not decrease. */
+	ulint*		write_size,
 	const char*	src_file,
 	ulint		src_line)
 {
diff --git a/storage/innobase/include/os0thread.h b/storage/innobase/include/os0thread.h
index 32fd1c7..0be2fa8 100644
--- a/storage/innobase/include/os0thread.h
+++ b/storage/innobase/include/os0thread.h
@@ -117,14 +117,11 @@ os_thread_create_func(
 	os_thread_id_t*		thread_id);	/*!< out: id of the created
 						thread, or NULL */
 
-/*****************************************************************//**
-Exits the current thread. */
+/** Exits the current thread. */
 void
-os_thread_exit(
-/*===========*/
-	void*	exit_value)	/*!< in: exit value; in Windows this void*
-				is cast as a DWORD */
+os_thread_exit()
 	UNIV_COLD MY_ATTRIBUTE((noreturn));
+
 /*****************************************************************//**
 Returns the thread identifier of current thread.
 @return current thread identifier */
diff --git a/storage/innobase/include/page0cur.h b/storage/innobase/include/page0cur.h
index 58be8b0..c111717 100644
--- a/storage/innobase/include/page0cur.h
+++ b/storage/innobase/include/page0cur.h
@@ -159,9 +159,10 @@ page_cur_tuple_insert(
 	mem_heap_t**	heap,	/*!< in/out: pointer to memory heap, or NULL */
 	ulint		n_ext,	/*!< in: number of externally stored columns */
 	mtr_t*		mtr,	/*!< in: mini-transaction handle, or NULL */
-	bool		use_cache = false);
+	bool		use_cache = false)
 				/*!< in: if true, then use record cache to
 				hold the tuple converted record. */
+	MY_ATTRIBUTE((nonnull(1,2,3,4,5), warn_unused_result));
 #endif /* !UNIV_HOTBACKUP */
 /***********************************************************//**
 Inserts a record next to page cursor. Returns pointer to inserted record if
diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h
index 8d1e5b1..3bb6221 100644
--- a/storage/innobase/include/page0page.h
+++ b/storage/innobase/include/page0page.h
@@ -264,7 +264,7 @@ page_header_get_offs(
 /*=================*/
 	const page_t*	page,	/*!< in: page */
 	ulint		field)	/*!< in: PAGE_FREE, ... */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*************************************************************//**
 Returns the pointer stored in the given header field, or NULL. */
@@ -530,7 +530,7 @@ bool
 page_is_leaf(
 /*=========*/
 	const page_t*	page)	/*!< in: page */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /************************************************************//**
 Determine whether the page is empty.
 @return true if the page is empty (PAGE_N_RECS = 0) */
@@ -539,7 +539,7 @@ bool
 page_is_empty(
 /*==========*/
 	const page_t*	page)	/*!< in: page */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /** Determine whether a page is an index root page.
 @param[in]	page	page frame
 @return true if the page is a root page of an index */
@@ -547,7 +547,7 @@ UNIV_INLINE
 bool
 page_is_root(
 	const page_t*	page)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /************************************************************//**
 Determine whether the page contains garbage.
 @return true if the page contains garbage (PAGE_GARBAGE is not 0) */
@@ -556,7 +556,7 @@ bool
 page_has_garbage(
 /*=============*/
 	const page_t*	page)	/*!< in: page */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /************************************************************//**
 Gets the pointer to the next record on the page.
 @return pointer to next record */
@@ -656,7 +656,7 @@ ibool
 page_rec_is_user_rec(
 /*=================*/
 	const rec_t*	rec)	/*!< in: record */
-	MY_ATTRIBUTE((const));
+	MY_ATTRIBUTE((warn_unused_result));
 /************************************************************//**
 TRUE if the record is the supremum record on a page.
 @return TRUE if the supremum record */
@@ -665,7 +665,7 @@ ibool
 page_rec_is_supremum(
 /*=================*/
 	const rec_t*	rec)	/*!< in: record */
-	MY_ATTRIBUTE((const));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /************************************************************//**
 TRUE if the record is the infimum record on a page.
@@ -675,7 +675,7 @@ ibool
 page_rec_is_infimum(
 /*================*/
 	const rec_t*	rec)	/*!< in: record */
-	MY_ATTRIBUTE((const));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /************************************************************//**
 true if the record is the first user record on a page.
@@ -686,7 +686,7 @@ page_rec_is_first(
 /*==============*/
 	const rec_t*	rec,	/*!< in: record */
 	const page_t*	page)	/*!< in: page */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /************************************************************//**
 true if the record is the second user record on a page.
@@ -697,7 +697,7 @@ page_rec_is_second(
 /*===============*/
 	const rec_t*	rec,	/*!< in: record */
 	const page_t*	page)	/*!< in: page */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /************************************************************//**
 true if the record is the last user record on a page.
@@ -708,7 +708,7 @@ page_rec_is_last(
 /*=============*/
 	const rec_t*	rec,	/*!< in: record */
 	const page_t*	page)	/*!< in: page */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /************************************************************//**
 true if the record is the second last user record on a page.
@@ -719,7 +719,7 @@ page_rec_is_second_last(
 /*====================*/
 	const rec_t*	rec,	/*!< in: record */
 	const page_t*	page)	/*!< in: page */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /***************************************************************//**
 Looks for the record which owns the given record.
diff --git a/storage/innobase/include/page0types.h b/storage/innobase/include/page0types.h
index 5dabcf2..fe56468 100644
--- a/storage/innobase/include/page0types.h
+++ b/storage/innobase/include/page0types.h
@@ -75,13 +75,14 @@ enum page_cur_mode_t {
 				 which extend it */
 
 /* These search mode is for search R-tree index. */
-	PAGE_CUR_CONTAIN	= 7,
-	PAGE_CUR_INTERSECT	= 8,
-	PAGE_CUR_WITHIN		= 9,
-	PAGE_CUR_DISJOINT	= 10,
-	PAGE_CUR_MBR_EQUAL	= 11,
-	PAGE_CUR_RTREE_INSERT	= 12,
-	PAGE_CUR_RTREE_LOCATE	= 13
+	PAGE_CUR_CONTAIN		= 7,
+	PAGE_CUR_INTERSECT		= 8,
+	PAGE_CUR_WITHIN			= 9,
+	PAGE_CUR_DISJOINT		= 10,
+	PAGE_CUR_MBR_EQUAL		= 11,
+	PAGE_CUR_RTREE_INSERT		= 12,
+	PAGE_CUR_RTREE_LOCATE		= 13,
+	PAGE_CUR_RTREE_GET_FATHER	= 14
 };
 
 
diff --git a/storage/innobase/include/page0zip.h b/storage/innobase/include/page0zip.h
index 20643b6..7b5df3d 100644
--- a/storage/innobase/include/page0zip.h
+++ b/storage/innobase/include/page0zip.h
@@ -2,7 +2,6 @@
 
 Copyright (c) 2005, 2016, Oracle and/or its affiliates. All Rights Reserved.
 Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2013, 2016, 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
@@ -88,7 +87,7 @@ ulint
 page_zip_get_size(
 /*==============*/
 	const page_zip_des_t*	page_zip)	/*!< in: compressed page */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 /**********************************************************************//**
 Set the size of a compressed page in bytes. */
 UNIV_INLINE
@@ -113,7 +112,7 @@ page_zip_rec_needs_ext(
 	ulint			comp,
 	ulint			n_fields,
 	const page_size_t&	page_size)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /**********************************************************************//**
 Determine the guaranteed free space on an empty page.
@@ -124,6 +123,15 @@ page_zip_empty_size(
 	ulint	n_fields,	/*!< in: number of columns in the index */
 	ulint	zip_size)	/*!< in: compressed page size in bytes */
 	MY_ATTRIBUTE((const));
+
+/** Check whether a tuple is too big for compressed table
+ at param[in]	index	dict index object
+ at param[in]	entry	entry for the index
+ at return	true if it's too big, otherwise false */
+bool
+page_zip_is_too_big(
+	const dict_index_t*	index,
+	const dtuple_t*		entry);
 #endif /* !UNIV_HOTBACKUP */
 
 /**********************************************************************//**
@@ -243,7 +251,7 @@ page_zip_max_ins_size(
 /*==================*/
 	const page_zip_des_t*	page_zip,/*!< in: compressed page */
 	ibool			is_clust)/*!< in: TRUE if clustered index */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /**********************************************************************//**
 Determine if enough space is available in the modification log.
@@ -257,7 +265,7 @@ page_zip_available(
 	ulint			length,	/*!< in: combined size of the record */
 	ulint			create)	/*!< in: nonzero=add the record to
 					the heap */
-	MY_ATTRIBUTE((nonnull, pure));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /**********************************************************************//**
 Write data to the uncompressed header portion of a page.  The data must
@@ -553,26 +561,6 @@ void
 page_zip_reset_stat_per_index();
 /*===========================*/
 
-#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
-from outside the buffer pool.
- at param ptr pointer to an uncompressed page frame
- at param page_zip compressed page descriptor
- at return TRUE if ptr and page_zip refer to the same block */
-# define PAGE_ZIP_MATCH(ptr, page_zip)					\
-	(((page_zip)->m_external					\
-	  && (page_align(ptr) + UNIV_PAGE_SIZE == (page_zip)->data))	\
-	  || buf_frame_get_page_zip(ptr) == (page_zip))
-#else /* !UNIV_HOTBACKUP */
-/** Check if a pointer to an uncompressed page matches a compressed page.
- at param ptr pointer to an uncompressed page frame
- at param page_zip compressed page descriptor
- at return TRUE if ptr and page_zip refer to the same block */
-# define PAGE_ZIP_MATCH(ptr, page_zip)				\
-	(page_align(ptr) + UNIV_PAGE_SIZE == (page_zip)->data)
-#endif /* !UNIV_HOTBACKUP */
-
 #ifdef UNIV_MATERIALIZE
 # undef UNIV_INLINE
 # define UNIV_INLINE	UNIV_INLINE_ORIGINAL
@@ -581,20 +569,6 @@ from outside the buffer pool.
 #ifndef UNIV_NONINL
 # include "page0zip.ic"
 #endif
-
-/** Issue a warning when the checksum that is stored in the page is valid,
-but different than the global setting innodb_checksum_algorithm.
- at param[in]	current_algo	current checksum algorithm
- at param[in]	page_checksum	page valid checksum
- at param[in]	space_id	tablespace id
- at 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);
-
 #endif /* !UNIV_INNOCHECKSUM */
 
 #endif /* page0zip_h */
diff --git a/storage/innobase/include/page0zip.ic b/storage/innobase/include/page0zip.ic
index cbb3660..9963fe0 100644
--- a/storage/innobase/include/page0zip.ic
+++ b/storage/innobase/include/page0zip.ic
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2005, 2016, 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
@@ -351,7 +351,6 @@ page_zip_write_header(
 {
 	ulint	pos;
 
-	ut_ad(PAGE_ZIP_MATCH(str, page_zip));
 	ut_ad(page_zip_simple_validate(page_zip));
 	UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
 
diff --git a/storage/innobase/include/pars0pars.h b/storage/innobase/include/pars0pars.h
index f52b35c..7e153d0 100644
--- a/storage/innobase/include/pars0pars.h
+++ b/storage/innobase/include/pars0pars.h
@@ -33,6 +33,7 @@ Created 11/19/1996 Heikki Tuuri
 #include "row0types.h"
 #include "trx0types.h"
 #include "ut0vec.h"
+#include "row0mysql.h"
 
 /** Type of the user functions. The first argument is always InnoDB-supplied
 and varies in type, while 'user_arg' is a user-supplied argument. The
@@ -418,18 +419,21 @@ que_fork_t*
 pars_stored_procedure_call(
 /*=======================*/
 	sym_node_t*	sym_node);	/*!< in: stored procedure name */
-/******************************************************************//**
-Completes a query graph by adding query thread and fork nodes
+/** Completes a query graph by adding query thread and fork nodes
 above it and prepares the graph for running. The fork created is of
 type QUE_FORK_MYSQL_INTERFACE.
+ at param[in]	node		root node for an incomplete query
+				graph, or NULL for dummy graph
+ at param[in]	trx		transaction handle
+ at param[in]	heap		memory heap from which allocated
+ at param[in]	prebuilt	row prebuilt structure
 @return query thread node to run */
 que_thr_t*
 pars_complete_graph_for_exec(
-/*=========================*/
-	que_node_t*	node,	/*!< in: root node for an incomplete
-				query graph, or NULL for dummy graph */
-	trx_t*		trx,	/*!< in: transaction handle */
-	mem_heap_t*	heap)	/*!< in: memory heap from which allocated */
+	que_node_t*	node,
+	trx_t*		trx,
+	mem_heap_t*	heap,
+	row_prebuilt_t*	prebuilt)
 	MY_ATTRIBUTE((nonnull(2,3), warn_unused_result));
 
 /****************************************************************//**
diff --git a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h
index 68a1115..3e90e0b 100644
--- a/storage/innobase/include/que0que.h
+++ b/storage/innobase/include/que0que.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.
 
 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
@@ -74,14 +74,16 @@ que_node_set_parent(
 /*================*/
 	que_node_t*	node,	/*!< in: graph node */
 	que_node_t*	parent);/*!< in: parent */
-/***********************************************************************//**
-Creates a query graph thread node.
+/** Creates a query graph thread node.
+ at param[in]	parent		parent node, i.e., a fork node
+ at param[in]	heap		memory heap where created
+ at param[in]	prebuilt	row prebuilt structure
 @return own: query thread node */
 que_thr_t*
 que_thr_create(
-/*===========*/
-	que_fork_t*	parent,	/*!< in: parent node, i.e., a fork node */
-	mem_heap_t*	heap);	/*!< in: memory heap where created */
+	que_fork_t*	parent,
+	mem_heap_t*	heap,
+	row_prebuilt_t*	prebuilt);
 /**********************************************************************//**
 Frees a query graph, but not the heap where it was created. Does not free
 explicit cursor declarations, they are freed in que_graph_free. */
@@ -398,6 +400,8 @@ struct que_thr_t{
 	ulint		fk_cascade_depth; /*!< maximum cascading call depth
 					supported for foreign key constraint
 					related delete/updates */
+	row_prebuilt_t*	prebuilt;	/*!< prebuilt structure processed by
+					the query thread */
 };
 
 #define QUE_THR_MAGIC_N		8476583
diff --git a/storage/innobase/include/read0read.h b/storage/innobase/include/read0read.h
index 9ba6acf..129341b 100644
--- a/storage/innobase/include/read0read.h
+++ b/storage/innobase/include/read0read.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2013, 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/read0types.h b/storage/innobase/include/read0types.h
index 230aac4..c83c7e0 100644
--- a/storage/innobase/include/read0types.h
+++ b/storage/innobase/include/read0types.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2016, 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
@@ -161,7 +161,7 @@ class ReadView {
 	bool changes_visible(
 		trx_id_t		id,
 		const table_name_t&	name) const
-		__attribute__((warn_unused_result))
+		MY_ATTRIBUTE((warn_unused_result))
 	{
 		ut_ad(id > 0);
 
diff --git a/storage/innobase/include/rem0cmp.h b/storage/innobase/include/rem0cmp.h
index 4016900..a594798 100644
--- a/storage/innobase/include/rem0cmp.h
+++ b/storage/innobase/include/rem0cmp.h
@@ -62,7 +62,7 @@ cmp_data_data(
 	ulint		len1,
 	const byte*	data2,
 	ulint		len2)
-	__attribute__((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
 
 /** Compare two data fields.
 @param[in] dfield1 data field; must have type field set
@@ -92,7 +92,22 @@ cmp_dtuple_rec_with_gis(
 	const rec_t*	rec,
 	const ulint*	offsets,
 	page_cur_mode_t	mode)
-	__attribute__((nonnull));
+	MY_ATTRIBUTE((nonnull));
+
+/** Compare a GIS data tuple to a physical record in rtree non-leaf node.
+We need to check the page number field, since we don't store pk field in
+rtree non-leaf node.
+ at param[in] dtuple data tuple
+ at param[in] rec R-tree record
+ at param[in] offsets rec_get_offsets(rec)
+ at param[in] mode compare mode
+ at retval negative if dtuple is less than rec */
+int
+cmp_dtuple_rec_with_gis_internal(
+	const dtuple_t*	dtuple,
+	const rec_t*	rec,
+	const ulint*	offsets);
+
 /** Compare a data tuple to a physical record.
 @param[in] dtuple data tuple
 @param[in] rec B-tree record
@@ -134,7 +149,7 @@ cmp_dtuple_rec_with_match_bytes(
 	const ulint*		offsets,
 	ulint*			matched_fields,
 	ulint*			matched_bytes)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /** Compare a data tuple to a physical record.
 @see cmp_dtuple_rec_with_match
 @param[in] dtuple data tuple
diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h
index 0edb73e..8490e7c 100644
--- a/storage/innobase/include/rem0rec.h
+++ b/storage/innobase/include/rem0rec.h
@@ -101,7 +101,7 @@ rec_get_next_ptr_const(
 /*===================*/
 	const rec_t*	rec,	/*!< in: physical record */
 	ulint		comp)	/*!< in: nonzero=compact page format */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 The following function is used to get the pointer of the next chained record
 on the same page.
@@ -112,7 +112,7 @@ rec_get_next_ptr(
 /*=============*/
 	rec_t*	rec,	/*!< in: physical record */
 	ulint	comp)	/*!< in: nonzero=compact page format */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 The following function is used to get the offset of the
 next chained record on the same page.
@@ -123,7 +123,7 @@ rec_get_next_offs(
 /*==============*/
 	const rec_t*	rec,	/*!< in: physical record */
 	ulint		comp)	/*!< in: nonzero=compact page format */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 The following function is used to set the next record offset field
 of an old-style record. */
@@ -153,7 +153,7 @@ ulint
 rec_get_n_fields_old(
 /*=================*/
 	const rec_t*	rec)	/*!< in: physical record */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 The following function is used to get the number of fields
 in a record.
@@ -164,7 +164,7 @@ rec_get_n_fields(
 /*=============*/
 	const rec_t*		rec,	/*!< in: physical record */
 	const dict_index_t*	index)	/*!< in: record descriptor */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Confirms the n_fields of the entry is sane with comparing the other
 record in the same page specified
@@ -178,7 +178,7 @@ rec_n_fields_is_sane(
 	dict_index_t*	index,
 	const rec_t*	rec,
 	const dtuple_t*	entry)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************//**
 The following function is used to get the number of records owned by the
@@ -189,7 +189,7 @@ ulint
 rec_get_n_owned_old(
 /*================*/
 	const rec_t*	rec)	/*!< in: old-style physical record */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 The following function is used to set the number of owned records. */
 UNIV_INLINE
@@ -208,7 +208,7 @@ ulint
 rec_get_n_owned_new(
 /*================*/
 	const rec_t*	rec)	/*!< in: new-style physical record */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 The following function is used to set the number of owned records. */
 UNIV_INLINE
@@ -229,7 +229,7 @@ rec_get_info_bits(
 /*==============*/
 	const rec_t*	rec,	/*!< in: physical record */
 	ulint		comp)	/*!< in: nonzero=compact page format */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 The following function is used to set the info bits of a record. */
 UNIV_INLINE
@@ -256,7 +256,7 @@ ulint
 rec_get_status(
 /*===========*/
 	const rec_t*	rec)	/*!< in: physical record */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************//**
 The following function is used to set the status bits of a new-style record. */
@@ -278,7 +278,7 @@ rec_get_info_and_status_bits(
 /*=========================*/
 	const rec_t*	rec,	/*!< in: physical record */
 	ulint		comp)	/*!< in: nonzero=compact page format */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 The following function is used to set the info and status
 bits of a record.  (Only compact records have status bits.) */
@@ -299,7 +299,7 @@ rec_get_deleted_flag(
 /*=================*/
 	const rec_t*	rec,	/*!< in: physical record */
 	ulint		comp)	/*!< in: nonzero=compact page format */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 The following function is used to set the deleted bit. */
 UNIV_INLINE
@@ -327,7 +327,7 @@ ibool
 rec_get_node_ptr_flag(
 /*==================*/
 	const rec_t*	rec)	/*!< in: physical record */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 The following function is used to get the order number
 of an old-style record in the heap of the index page.
@@ -337,7 +337,7 @@ ulint
 rec_get_heap_no_old(
 /*================*/
 	const rec_t*	rec)	/*!< in: physical record */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 The following function is used to set the heap number
 field in an old-style record. */
@@ -357,7 +357,7 @@ ulint
 rec_get_heap_no_new(
 /*================*/
 	const rec_t*	rec)	/*!< in: physical record */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 The following function is used to set the heap number
 field in a new-style record. */
@@ -377,7 +377,7 @@ ibool
 rec_get_1byte_offs_flag(
 /*====================*/
 	const rec_t*	rec)	/*!< in: physical record */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************//**
 The following function is used to set the 1-byte offsets flag. */
@@ -400,7 +400,7 @@ rec_1_get_field_end_info(
 /*=====================*/
 	const rec_t*	rec,	/*!< in: record */
 	ulint		n)	/*!< in: field index */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************//**
 Returns the offset of nth field end if the record is stored in the 2-byte
@@ -414,7 +414,7 @@ rec_2_get_field_end_info(
 /*=====================*/
 	const rec_t*	rec,	/*!< in: record */
 	ulint		n)	/*!< in: field index */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************//**
 Returns nonzero if the field is stored off-page.
@@ -426,7 +426,7 @@ rec_2_is_field_extern(
 /*==================*/
 	const rec_t*	rec,	/*!< in: record */
 	ulint		n)	/*!< in: field index */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************//**
 Determine how many of the first n columns in a compact
@@ -545,7 +545,7 @@ rec_get_nth_field_size(
 /*===================*/
 	const rec_t*	rec,	/*!< in: record */
 	ulint		n)	/*!< in: index of the field */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /************************************************************//**
 The following function is used to get an offset to the nth
 data field in a record.
@@ -570,7 +570,7 @@ ulint
 rec_offs_comp(
 /*==========*/
 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 Determine if the offsets are for a record containing
 externally stored columns.
@@ -580,7 +580,7 @@ ulint
 rec_offs_any_extern(
 /*================*/
 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 Determine if the offsets are for a record containing null BLOB pointers.
 @return first field containing a null BLOB pointer, or NULL if none found */
@@ -590,7 +590,7 @@ rec_offs_any_null_extern(
 /*=====================*/
 	const rec_t*	rec,		/*!< in: record */
 	const ulint*	offsets)	/*!< in: rec_get_offsets(rec) */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 Returns nonzero if the extern bit is set in nth field of rec.
 @return nonzero if externally stored */
@@ -600,7 +600,7 @@ rec_offs_nth_extern(
 /*================*/
 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
 	ulint		n)	/*!< in: nth field */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Mark the nth field as externally stored.
 @param[in]	offsets		array returned by rec_get_offsets()
@@ -618,7 +618,7 @@ rec_offs_nth_sql_null(
 /*==================*/
 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
 	ulint		n)	/*!< in: nth field */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /******************************************************//**
 Gets the physical size of a field.
 @return length of field */
@@ -628,7 +628,7 @@ rec_offs_nth_size(
 /*==============*/
 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
 	ulint		n)	/*!< in: nth field */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************//**
 Returns the number of extern bits set in a record.
@@ -638,7 +638,7 @@ ulint
 rec_offs_n_extern(
 /*==============*/
 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /***********************************************************//**
 This is used to modify the value of an already existing field in a record.
 The previous value must have exactly the same size as the new value. If len
@@ -670,7 +670,7 @@ ulint
 rec_get_data_size_old(
 /*==================*/
 	const rec_t*	rec)	/*!< in: physical record */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**********************************************************//**
 The following function returns the number of allocated elements
 for an array of offsets.
@@ -680,7 +680,7 @@ ulint
 rec_offs_get_n_alloc(
 /*=================*/
 	const ulint*	offsets)/*!< in: array for rec_get_offsets() */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**********************************************************//**
 The following function sets the number of allocated elements
 for an array of offsets. */
@@ -702,7 +702,7 @@ ulint
 rec_offs_n_fields(
 /*==============*/
 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**********************************************************//**
 The following function returns the data size of a physical
 record, that is the sum of field lengths. SQL null fields
@@ -714,7 +714,7 @@ ulint
 rec_offs_data_size(
 /*===============*/
 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**********************************************************//**
 Returns the total size of record minus data size of record.
 The value returned by the function is the distance from record
@@ -725,7 +725,7 @@ ulint
 rec_offs_extra_size(
 /*================*/
 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**********************************************************//**
 Returns the total size of a physical record.
 @return size */
@@ -734,7 +734,7 @@ ulint
 rec_offs_size(
 /*==========*/
 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 #ifdef UNIV_DEBUG
 /**********************************************************//**
 Returns a pointer to the start of the record.
@@ -745,7 +745,7 @@ rec_get_start(
 /*==========*/
 	const rec_t*	rec,	/*!< in: pointer to record */
 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**********************************************************//**
 Returns a pointer to the end of the record.
 @return pointer to end */
@@ -755,7 +755,7 @@ rec_get_end(
 /*========*/
 	const rec_t*	rec,	/*!< in: pointer to record */
 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
-	MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 #else /* UNIV_DEBUG */
 # define rec_get_start(rec, offsets) ((rec) - rec_offs_extra_size(offsets))
 # define rec_get_end(rec, offsets) ((rec) + rec_offs_data_size(offsets))
@@ -786,7 +786,7 @@ rec_get_converted_size_temp(
 	const dtuple_t*		v_entry,/*!< in: dtuple contains virtual column
 					data */
 	ulint*			extra)	/*!< out: extra size */
-	MY_ATTRIBUTE((warn_unused_result, nonnull(1)));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************//**
 Determine the offset to each field in temporary file.
@@ -845,7 +845,7 @@ rec_fold(
 	ulint		n_fields,
 	ulint		n_bytes,
 	index_id_t	tree_id)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 #endif /* !UNIV_HOTBACKUP */
 /*********************************************************//**
 Builds a physical record out of a data tuple and
@@ -860,7 +860,7 @@ rec_convert_dtuple_to_rec(
 	const dtuple_t*		dtuple,	/*!< in: data tuple */
 	ulint			n_ext)	/*!< in: number of
 					externally stored columns */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /**********************************************************//**
 Returns the extra size of an old-style physical record if we know its
 data size and number of fields.
@@ -898,7 +898,7 @@ rec_get_converted_size_comp(
 	const dfield_t*		fields,	/*!< in: array of data fields */
 	ulint			n_fields,/*!< in: number of data fields */
 	ulint*			extra)	/*!< out: extra size */
-	MY_ATTRIBUTE((nonnull(1)));
+	MY_ATTRIBUTE((nonnull(1,3)));
 /**********************************************************//**
 The following function returns the size of a data tuple when converted to
 a physical record.
@@ -962,7 +962,7 @@ rec_print_mbr_rec(
 	FILE*		file,	/*!< in: file where to print */
 	const rec_t*	rec,	/*!< in: physical record */
 	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
-	__attribute__((nonnull));
+	MY_ATTRIBUTE((nonnull));
 /***************************************************************//**
 Prints a physical record. */
 void
@@ -1124,6 +1124,7 @@ int wsrep_rec_get_foreign_key(
 	dict_index_t*	index_ref,  /* in: index for referenced table */
 	ibool		new_protocol); /* in: protocol > 1 */
 #endif /* WITH_WSREP */
+
 #ifndef UNIV_NONINL
 #include "rem0rec.ic"
 #endif
diff --git a/storage/innobase/include/rem0rec.ic b/storage/innobase/include/rem0rec.ic
index 4d2cbcb..b855a39 100644
--- a/storage/innobase/include/rem0rec.ic
+++ b/storage/innobase/include/rem0rec.ic
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1994, 2016, 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
diff --git a/storage/innobase/include/row0ftsort.h b/storage/innobase/include/row0ftsort.h
index c06327c..7e39fe3 100644
--- a/storage/innobase/include/row0ftsort.h
+++ b/storage/innobase/include/row0ftsort.h
@@ -94,7 +94,7 @@ struct fts_psort_t {
 	ulint			state;		/*!< parent thread state */
 	fts_doc_list_t		fts_doc_list;	/*!< doc list to process */
 	fts_psort_common_t*	psort_common;	/*!< ptr to all psort info */
-	os_thread_id_t		thread_hdl;	/*!< thread handler */
+	os_thread_t		thread_hdl;	/*!< thread handler */
 	dberr_t			error;		/*!< db error during psort */
 	ulint			memory_used;	/*!< memory used by fts_doc_list */
 	ib_mutex_t		mutex;		/*!< mutex for fts_doc_list */
diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h
index 48a3044..4038c32 100644
--- a/storage/innobase/include/row0ins.h
+++ b/storage/innobase/include/row0ins.h
@@ -97,7 +97,7 @@ row_ins_clust_index_entry_low(
 	bool		dup_chk_only)
 				/*!< in: if true, just do duplicate check
 				and return. don't execute actual insert. */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /***************************************************************//**
 Tries to insert an entry into a secondary index. If a record with exactly the
@@ -125,7 +125,7 @@ row_ins_sec_index_entry_low(
 	bool		dup_chk_only)
 				/*!< in: if true, just do duplicate check
 				and return. don't execute actual insert. */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /** Sets the values of the dtuple fields in entry from the values of appropriate
 columns in row.
 @param[in]	index	index handler
@@ -178,7 +178,7 @@ row_ins_clust_index_entry(
 	bool		dup_chk_only)
 				/*!< in: if true, just do duplicate check
 				and return. don't execute actual insert. */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /***************************************************************//**
 Inserts an entry into a secondary index. Tries first optimistic,
 then pessimistic descent down the tree. If the entry matches enough
@@ -194,7 +194,7 @@ row_ins_sec_index_entry(
 	bool		dup_chk_only)
 				/*!< in: if true, just do duplicate check
 				and return. don't execute actual insert. */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /***********************************************************//**
 Inserts a row to a table. This is a high-level function used in
 SQL execution graphs.
diff --git a/storage/innobase/include/row0log.h b/storage/innobase/include/row0log.h
index 80571eb..c8db44f 100644
--- a/storage/innobase/include/row0log.h
+++ b/storage/innobase/include/row0log.h
@@ -56,8 +56,9 @@ row_log_allocate(
 	const dtuple_t*	add_cols,
 				/*!< in: default values of
 				added columns, or NULL */
-	const ulint*	col_map)/*!< in: mapping of old column
+	const ulint*	col_map,/*!< in: mapping of old column
 				numbers to new ones, or NULL if !table */
+	const char*	path)	/*!< in: where to create temporary file */
 	MY_ATTRIBUTE((nonnull(1), warn_unused_result));
 
 /******************************************************//**
@@ -112,6 +113,16 @@ row_log_table_get_error(
 					that is being rebuilt online */
 	MY_ATTRIBUTE((nonnull, warn_unused_result));
 
+/** Check whether a virtual column is indexed in the new table being
+created during alter table
+ at param[in]	index	cluster index
+ at param[in]	v_no	virtual column number
+ at return true if it is indexed, else false */
+bool
+row_log_col_is_indexed(
+	const dict_index_t*	index,
+	ulint			v_no);
+
 /******************************************************//**
 Logs a delete operation to a table that is being rebuilt.
 This will be merged in row_log_table_apply_delete(). */
@@ -208,7 +219,7 @@ row_log_table_apply(
 	dict_table_t*		old_table,
 	struct TABLE*		table,
 	ut_stage_alter_t*	stage)
-__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /******************************************************//**
 Get the latest transaction ID that has invoked row_log_online_op()
@@ -235,7 +246,7 @@ row_log_apply(
 	dict_index_t*		index,
 	struct TABLE*		table,
 	ut_stage_alter_t*	stage)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 #ifdef HAVE_PSI_STAGE_INTERFACE
 /** Estimate how much work is to be done by the log apply phase
diff --git a/storage/innobase/include/row0merge.h b/storage/innobase/include/row0merge.h
index 4493df5..f3b5860 100644
--- a/storage/innobase/include/row0merge.h
+++ b/storage/innobase/include/row0merge.h
@@ -152,6 +152,7 @@ row_merge_dup_report(
 	row_merge_dup_t*	dup,	/*!< in/out: for reporting duplicates */
 	const dfield_t*		entry)	/*!< in: duplicate index entry */
 	MY_ATTRIBUTE((nonnull));
+
 /*********************************************************************//**
 Sets an exclusive lock on a table, for the duration of creating indexes.
 @return error code or DB_SUCCESS */
@@ -161,7 +162,8 @@ row_merge_lock_table(
 	trx_t*		trx,		/*!< in/out: transaction */
 	dict_table_t*	table,		/*!< in: table to lock */
 	enum lock_mode	mode)		/*!< in: LOCK_X or LOCK_S */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((nonnull(1,2), warn_unused_result));
+
 /*********************************************************************//**
 Drop indexes that were created before an error occurred.
 The data dictionary must have been locked exclusively by the caller,
@@ -172,6 +174,7 @@ row_merge_drop_indexes_dict(
 	trx_t*		trx,	/*!< in/out: dictionary transaction */
 	table_id_t	table_id)/*!< in: table identifier */
 	MY_ATTRIBUTE((nonnull));
+
 /*********************************************************************//**
 Drop those indexes which were created before an error occurred.
 The data dictionary must have been locked exclusively by the caller,
@@ -184,6 +187,7 @@ row_merge_drop_indexes(
 	ibool		locked)	/*!< in: TRUE=table locked,
 				FALSE=may need to do a lazy drop */
 	MY_ATTRIBUTE((nonnull));
+
 /*********************************************************************//**
 Drop all partially created indexes during crash recovery. */
 void
@@ -195,7 +199,8 @@ UNIV_PFS_IO defined, register the file descriptor with Performance Schema.
 @param[in]	path	location for creating temporary merge files.
 @return File descriptor */
 int
-row_merge_file_create_low(void)
+row_merge_file_create_low(
+	const char*	path)
 	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Destroy a merge file. And de-register the file from Performance Schema
@@ -214,7 +219,9 @@ char*
 row_make_new_pathname(
 /*==================*/
 	dict_table_t*	table,		/*!< in: table to be renamed */
-	const char*	new_name);	/*!< in: new name */
+	const char*	new_name)	/*!< in: new name */
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
+
 /*********************************************************************//**
 Rename the tables in the data dictionary.  The data dictionary must
 have been locked exclusively by the caller, because the transaction
@@ -242,7 +249,8 @@ row_merge_rename_index_to_add(
 	trx_t*		trx,		/*!< in/out: transaction */
 	table_id_t	table_id,	/*!< in: table identifier */
 	index_id_t	index_id)	/*!< in: index identifier */
-	MY_ATTRIBUTE((nonnull));
+	MY_ATTRIBUTE((nonnull(1), warn_unused_result));
+
 /*********************************************************************//**
 Rename an index in the dictionary that is to be dropped. The data
 dictionary must have been locked exclusively by the caller, because
@@ -254,7 +262,8 @@ row_merge_rename_index_to_drop(
 	trx_t*		trx,		/*!< in/out: transaction */
 	table_id_t	table_id,	/*!< in: table identifier */
 	index_id_t	index_id)	/*!< in: index identifier */
-	MY_ATTRIBUTE((nonnull));
+	MY_ATTRIBUTE((nonnull(1), warn_unused_result));
+
 /** Create the index and load in to the dictionary.
 @param[in,out]	trx		trx (sets error_state)
 @param[in,out]	table		the index is on this table
@@ -270,7 +279,9 @@ row_merge_create_index(
 	dict_table_t*		table,
 	const index_def_t*	index_def,
 	const dict_add_v_col_t*	add_v,
-	const char**		col_names);
+	const char**		col_names)
+	MY_ATTRIBUTE((warn_unused_result));
+
 /*********************************************************************//**
 Check if a transaction can use an index.
 @return TRUE if index can be used by the transaction else FALSE */
@@ -278,7 +289,9 @@ ibool
 row_merge_is_index_usable(
 /*======================*/
 	const trx_t*		trx,	/*!< in: transaction */
-	const dict_index_t*	index);	/*!< in: index to check */
+	const dict_index_t*	index)	/*!< in: index to check */
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
+
 /*********************************************************************//**
 Drop a table. The caller must have ensured that the background stats
 thread is not processing the table. This can be done by calling
@@ -290,7 +303,7 @@ row_merge_drop_table(
 /*=================*/
 	trx_t*		trx,		/*!< in: transaction */
 	dict_table_t*	table)		/*!< in: table instance to drop */
-	MY_ATTRIBUTE((nonnull));
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
 
 /** Build indexes on a table by reading a clustered index, creating a temporary
 file containing index entries, merge sorting these index entries and inserting
@@ -317,6 +330,8 @@ existing order
 ALTER TABLE. stage->begin_phase_read_pk() will be called at the beginning of
 this function and it will be passed to other functions for further accounting.
 @param[in]	add_v		new virtual columns added along with indexes
+ at param[in]	eval_table	mysql table used to evaluate virtual column
+				value, see innobase_get_computed_value().
 @return DB_SUCCESS or error code */
 dberr_t
 row_merge_build_indexes(
@@ -334,8 +349,9 @@ row_merge_build_indexes(
 	ib_sequence_t&		sequence,
 	bool			skip_pk_sort,
 	ut_stage_alter_t*	stage,
-	const dict_add_v_col_t*	add_v)
-__attribute__((warn_unused_result));
+	const dict_add_v_col_t*	add_v,
+	struct TABLE*		eval_table)
+	MY_ATTRIBUTE((warn_unused_result));
 
 /********************************************************************//**
 Write a buffer to a block. */
@@ -346,6 +362,7 @@ row_merge_buf_write(
 	const merge_file_t*	of,	/*!< in: output file */
 	row_merge_block_t*	block)	/*!< out: buffer for writing to file */
 	MY_ATTRIBUTE((nonnull));
+
 /********************************************************************//**
 Sort a buffer. */
 void
@@ -355,6 +372,7 @@ row_merge_buf_sort(
 	row_merge_dup_t*	dup)	/*!< in/out: reporter of duplicates
 					(NULL if non-unique index) */
 	MY_ATTRIBUTE((nonnull(1)));
+
 /********************************************************************//**
 Write a merge block to the file system.
 @return TRUE if request was successful, FALSE if fail */
@@ -367,7 +385,8 @@ row_merge_write(
 	const void*	buf,	/*!< in: data */
 	fil_space_crypt_t*	crypt_data,	/*!< in: table crypt data */
 	void*		crypt_buf,		/*!< in: crypt buf or NULL */
-	ulint		space);			/*!< in: space id */
+	ulint		space)			/*!< in: space id */
+	MY_ATTRIBUTE((warn_unused_result));
 
 /********************************************************************//**
 Empty a sort buffer.
@@ -384,7 +403,9 @@ row_merge_buf_empty(
 @return file descriptor, or -1 on failure */
 int
 row_merge_file_create(
-	merge_file_t*	merge_file);
+	merge_file_t*	merge_file,
+	const char*	path)
+	MY_ATTRIBUTE((warn_unused_result, nonnull));
 
 /** Merge disk files.
 @param[in]	trx	transaction
@@ -392,6 +413,12 @@ row_merge_file_create(
 @param[in,out]	file	file containing index entries
 @param[in,out]	block	3 buffers
 @param[in,out]	tmpfd	temporary file handle
+ at param[in]      update_progress true, if we should update progress status
+ at param[in]      pct_progress total progress percent until now
+ at param[in]      pct_ocst current progress percent
+ at param[in]      crypt_data tale crypt data
+ at param[in]      crypt_block crypt buf or NULL
+ at param[in]      space    space_id
 @param[in,out]	stage	performance schema accounting object, used by
 ALTER TABLE. If not NULL, stage->begin_phase_sort() will be called initially
 and then stage->inc() will be called for each record processed.
@@ -399,21 +426,20 @@ and then stage->inc() will be called for each record processed.
 dberr_t
 row_merge_sort(
 /*===========*/
-	trx_t*			trx,	/*!< in: transaction */
-	const row_merge_dup_t*	dup,	/*!< in: descriptor of
-					index being created */
-	merge_file_t*		file,	/*!< in/out: file containing
-					index entries */
-	row_merge_block_t*	block,	/*!< in/out: 3 buffers */
-	int*			tmpfd,	/*!< in/out: temporary file handle */
-	const bool		update_progress, /*!< in: update progress status variable or not */
-	const float		pct_progress, /*!< in: total progress percent until now */
-	const float		pct_cost, /*!< in: current progress percent */
-	fil_space_crypt_t*	crypt_data,/*!< in: table crypt data */
-	row_merge_block_t*	crypt_block, /*!< in: crypt buf or NULL */
-	ulint			space,	   /*!< in: space id */
+	trx_t*			trx,
+	const row_merge_dup_t*	dup,
+	merge_file_t*		file,
+	row_merge_block_t*	block,
+	int*			tmpfd,
+	const bool		update_progress,
+	const float		pct_progress,
+	const float		pct_cost,
+	fil_space_crypt_t*	crypt_data,
+	row_merge_block_t*	crypt_block,
+	ulint			space,
 	ut_stage_alter_t*	stage = NULL)
-	__attribute__((nonnull(1,2,3,4,5)));
+	MY_ATTRIBUTE((warn_unused_result));
+
 /*********************************************************************//**
 Allocate a sort buffer.
 @return own: sort buffer */
@@ -422,6 +448,7 @@ row_merge_buf_create(
 /*=================*/
 	dict_index_t*	index)	/*!< in: secondary index */
 	MY_ATTRIBUTE((warn_unused_result, nonnull, malloc));
+
 /*********************************************************************//**
 Deallocate a sort buffer. */
 void
@@ -429,6 +456,7 @@ row_merge_buf_free(
 /*===============*/
 	row_merge_buf_t*	buf)	/*!< in,own: sort buffer to be freed */
 	MY_ATTRIBUTE((nonnull));
+
 /*********************************************************************//**
 Destroy a merge file. */
 void
@@ -436,6 +464,7 @@ row_merge_file_destroy(
 /*===================*/
 	merge_file_t*	merge_file)	/*!< in/out: merge file structure */
 	MY_ATTRIBUTE((nonnull));
+
 /********************************************************************//**
 Read a merge block from the file system.
 @return TRUE if request was successful, FALSE if fail */
@@ -449,7 +478,8 @@ row_merge_read(
 	row_merge_block_t*	buf,	/*!< out: data */
 	fil_space_crypt_t*	crypt_data,/*!< in: table crypt data */
 	row_merge_block_t*	crypt_buf, /*!< in: crypt buf or NULL */
-	ulint			space);	   /*!< in: space id */
+	ulint			space)	   /*!< in: space id */
+	MY_ATTRIBUTE((warn_unused_result));
 
 /********************************************************************//**
 Read a merge record.
@@ -470,5 +500,5 @@ row_merge_read_rec(
 	fil_space_crypt_t*	crypt_data,/*!< in: table crypt data */
 	row_merge_block_t*	crypt_block, /*!< in: crypt buf or NULL */
 	ulint			space)	   /*!< in: space id */
-	__attribute__((nonnull(1,2,3,4,6,7,8), warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 #endif /* row0merge.h */
diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
index 5b19573..2d508c1 100644
--- a/storage/innobase/include/row0mysql.h
+++ b/storage/innobase/include/row0mysql.h
@@ -130,7 +130,7 @@ row_mysql_read_geometry(
 					MySQL format */
 	ulint		col_len)	/*!< in: BLOB reference length
 					(not BLOB length) */
-	__attribute__((nonnull(1,2), warn_unused_result));
+	MY_ATTRIBUTE((nonnull(1,2), warn_unused_result));
 /**************************************************************//**
 Pad a column with spaces. */
 void
@@ -229,6 +229,7 @@ row_lock_table_autoinc_for_mysql(
 	row_prebuilt_t*	prebuilt)	/*!< in: prebuilt struct in the MySQL
 					table handle */
 	MY_ATTRIBUTE((nonnull, warn_unused_result));
+
 /*********************************************************************//**
 Sets a table lock on the table mentioned in prebuilt.
 @return error code or DB_SUCCESS */
@@ -253,7 +254,7 @@ dberr_t
 row_insert_for_mysql(
 	const byte*		mysql_rec,
 	row_prebuilt_t*		prebuilt)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*********************************************************************//**
 Builds a dummy query graph used in selects. */
@@ -289,7 +290,7 @@ dberr_t
 row_update_for_mysql(
 	const byte*		mysql_rec,
 	row_prebuilt_t*		prebuilt)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** Delete all rows for the given table by freeing/truncating indexes.
 @param[in,out]	table	table handler
@@ -297,7 +298,7 @@ row_update_for_mysql(
 dberr_t
 row_delete_all_rows(
 	dict_table_t*	table)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /** This can only be used when srv_locks_unsafe_for_binlog is TRUE or this
 session is using a READ COMMITTED or READ UNCOMMITTED isolation level.
@@ -381,13 +382,14 @@ row_create_table_for_mysql(
 	dict_table_t*	table,	/*!< in, own: table definition
 				(will be freed, or on DB_SUCCESS
 				added to the data dictionary cache) */
-        const char*     compression,
-                                /*!< in: compression algorithm to use,
-                                can be NULL */
+	const char*	compression,
+				/*!< in: compression algorithm to use,
+				can be NULL */
 	trx_t*		trx,	/*!< in/out: transaction */
 	bool		commit,	/*!< in: if true, commit the transaction */
 	fil_encryption_t mode,	/*!< in: encryption mode */
-	ulint		key_id);/*!< in: encryption key_id */
+	ulint		key_id)	/*!< in: encryption key_id */
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*********************************************************************//**
 Does an index creation operation for MySQL. TODO: currently failure
@@ -407,7 +409,7 @@ row_create_index_for_mysql(
 					then checked for not being too
 					large. */
 	dict_table_t*	handler)	/* ! in/out: table handler. */
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((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
@@ -438,7 +440,7 @@ row_table_add_foreign_constraints(
 	size_t			sql_length,
 	const char*		name,
 	ibool			reject_fks)
-	__attribute__((warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /*********************************************************************//**
 The master thread in srv0srv.cc calls this regularly to drop tables which
@@ -489,8 +491,8 @@ row_drop_table_for_mysql(
 	trx_t*		trx,	/*!< in: dictionary transaction handle */
 	bool		drop_db,/*!< in: true=dropping whole database */
 	ibool		create_failed,/*!<in: TRUE=create table failed
-				       because e.g. foreign key column
-				       type mismatch. */
+					because e.g. foreign key column
+					type mismatch. */
 	bool		nonatomic = true,
 				/*!< in: whether it is permitted
 				to release and reacquire dict_operation_lock */
@@ -557,7 +559,7 @@ row_rename_partitions_for_mysql(
 	const char*	old_name,
 	const char*	new_name,
 	trx_t*		trx)
-	__attribute__((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
 
 /*********************************************************************//**
 Scans an index for either COOUNT(*) or CHECK TABLE.
@@ -576,7 +578,7 @@ row_scan_index_for_mysql(
 						false=count the rows only */
 	ulint*			n_rows)		/*!< out: number of entries
 						seen in the consistent read */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 /*********************************************************************//**
 Initialize this module */
 void
@@ -910,6 +912,14 @@ struct row_prebuilt_t {
 	/** Disable prefetch. */
 	bool		m_no_prefetch;
 
+	/** Return materialized key for secondary index scan */
+	bool		m_read_virtual_key;
+
+	/** The MySQL table object */
+	TABLE*		m_mysql_table;
+
+	/** limit value to avoid fts result overflow */
+	ulonglong	m_fts_limit;
 };
 
 /** Callback for row_mysql_sys_index_iterate() */
@@ -926,22 +936,42 @@ struct SysIndexCallback {
 @param[in,out]	row		the data row
 @param[in]	col		virtual column
 @param[in]	index		index on the virtual column
- at param[in,out]	my_rec		MySQL record to store the rows
 @param[in,out]	local_heap	heap memory for processing large data etc.
 @param[in,out]	heap		memory heap that copies the actual index row
 @param[in]	ifield		index field
- at param[in]	in_purge	whether this is called by purge
+ at param[in]	thd		MySQL thread handle
+ at param[in,out]	mysql_table	mysql table object
+ at param[in]	old_table	during ALTER TABLE, this is the old table
+				or NULL.
+ at param[in]	parent_update	update vector for the parent row
+ at param[in]	foreign		foreign key information
 @return the field filled with computed value */
 dfield_t*
 innobase_get_computed_value(
 	const dtuple_t*		row,
 	const dict_v_col_t*	col,
 	const dict_index_t*	index,
-	byte*			my_rec,
 	mem_heap_t**		local_heap,
 	mem_heap_t*		heap,
 	const dict_field_t*	ifield,
-	bool			in_purge);
+	THD*			thd,
+	TABLE*			mysql_table,
+	const dict_table_t*	old_table,
+	upd_t*			parent_update,
+	dict_foreign_t*		foreign);
+
+/** Get the computed value by supplying the base column values.
+ at param[in,out]	table	the table whose virtual column template to be built */
+void
+innobase_init_vc_templ(
+	dict_table_t*	table);
+
+/** Change dbname and table name in table->vc_templ.
+ at param[in,out]	table	the table whose virtual column template
+dbname and tbname to be renamed. */
+void
+innobase_rename_vc_templ(
+	dict_table_t*	table);
 
 #define ROW_PREBUILT_FETCH_MAGIC_N	465765687
 
@@ -964,4 +994,10 @@ innobase_get_computed_value(
 #include "row0mysql.ic"
 #endif
 
+#ifdef UNIV_DEBUG
+/** Wait for the background drop list to become empty. */
+void
+row_wait_for_background_drop_list_empty();
+#endif /* UNIV_DEBUG */
+
 #endif /* row0mysql.h */
diff --git a/storage/innobase/include/row0purge.h b/storage/innobase/include/row0purge.h
index f640dfa..32a9898 100644
--- a/storage/innobase/include/row0purge.h
+++ b/storage/innobase/include/row0purge.h
@@ -44,7 +44,7 @@ purge_node_t*
 row_purge_node_create(
 	que_thr_t*	parent,
 	mem_heap_t*	heap)
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
+	MY_ATTRIBUTE((warn_unused_result));
 
 /***********************************************************//**
 Determines if it is possible to remove a secondary index entry.
diff --git a/storage/innobase/include/row0row.h b/storage/innobase/include/row0row.h
index 4fd9328..93ff90d 100644
--- a/storage/innobase/