MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:August 30 2006 11:25am
Subject:bk commit into 5.1 tree (anozdrin:1.2285)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of alik. When alik does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2006-08-30 15:25:26+04:00, anozdrin@stripped +105 -0
  Merge booka.site:/home/alik/MySQL/devel/5.0-rt
  into  booka.site:/home/alik/MySQL/devel/5.1-rt-merged
  MERGE: 1.1810.1697.133

  BUILD/check-cpu@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.13.1.1

  BitKeeper/deleted/.del-im_check_os.inc@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.1.1.1

  BitKeeper/deleted/.del-im_check_os.inc@stripped, 2006-08-30 14:31:54+04:00, anozdrin@stripped +0 -0
    Merge rename: mysql-test/include/im_check_os.inc -> BitKeeper/deleted/.del-im_check_os.inc

  BitKeeper/deleted/.del-im_options_set.imtest~b53d9d60e5684833@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.2.2.2

  BitKeeper/deleted/.del-im_options_set.imtest~b53d9d60e5684833@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: mysql-test/t/im_options_set.imtest -> BitKeeper/deleted/.del-im_options_set.imtest~b53d9d60e5684833

  BitKeeper/deleted/.del-im_options_set.result~59278f56be61d921@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.4.2.2

  BitKeeper/deleted/.del-im_options_set.result~59278f56be61d921@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: mysql-test/r/im_options_set.result -> BitKeeper/deleted/.del-im_options_set.result~59278f56be61d921

  BitKeeper/deleted/.del-im_options_unset.imtest~768eb186b51d0048@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.2.2.2

  BitKeeper/deleted/.del-im_options_unset.imtest~768eb186b51d0048@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: mysql-test/t/im_options_unset.imtest -> BitKeeper/deleted/.del-im_options_unset.imtest~768eb186b51d0048

  BitKeeper/deleted/.del-im_options_unset.result~20a4790cd3c70a4f@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.4.2.2

  BitKeeper/deleted/.del-im_options_unset.result~20a4790cd3c70a4f@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: mysql-test/r/im_options_unset.result -> BitKeeper/deleted/.del-im_options_unset.result~20a4790cd3c70a4f

  client/mysqltest.c@stripped, 2006-08-30 14:39:32+04:00, anozdrin@stripped +3 -0
    MERGE: 1.155.9.50

  configure.in@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.245.1.152

  include/config-netware.h@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.14.2.1

  include/mysql_com.h@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.100.1.5

  mysql-test/lib/mtr_io.pl@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.3.1.1

  mysql-test/lib/mtr_process.pl@stripped, 2006-08-30 15:25:22+04:00, anozdrin@stripped +36 -63
    Manually merged.
    MERGE: 1.25.2.7

  mysql-test/mysql-test-run.pl@stripped, 2006-08-30 15:25:22+04:00, anozdrin@stripped +3 -7
    Manually merged.
    MERGE: 1.30.1.81

  mysql-test/r/distinct.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.46.1.1

  mysql-test/r/func_time.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.47.1.19

  mysql-test/r/grant.result@stripped, 2006-08-30 15:23:35+04:00, anozdrin@stripped +0 -26
    ul
    ul
    ul
    ul
    ul
    ul
    ul
    ul
    ul
    ul
    ul
    ul
    ul
    ul
    ul
    MERGE: 1.37.1.22

  mysql-test/r/group_by.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.69.1.1

  mysql-test/r/im_daemon_life_cycle.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.2.1.3

  mysql-test/r/im_life_cycle.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.3.1.6

  mysql-test/r/im_utils.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.1.1.4

  mysql-test/r/innodb_mysql.result@stripped, 2006-08-30 15:23:53+04:00, anozdrin@stripped +0 -40
    MERGE: 1.3.4.3

  mysql-test/r/join_outer.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.44.1.7

  mysql-test/r/ndb_condition_pushdown.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.15.1.6

  mysql-test/r/ps.result@stripped, 2006-08-30 15:23:55+04:00, anozdrin@stripped +0 -15
    MERGE: 1.56.1.16

  mysql-test/r/range.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.44.1.4

  mysql-test/r/select.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.121.1.17

  mysql-test/r/sp-error.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.102.1.6

  mysql-test/r/sp.result@stripped, 2006-08-30 15:23:56+04:00, anozdrin@stripped +2 -140
    MERGE: 1.170.1.40

  mysql-test/r/subselect.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.134.1.20

  mysql-test/r/trigger.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.29.1.16

  mysql-test/r/type_datetime.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.30.1.2

  mysql-test/r/type_varchar.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.8.1.1

  mysql-test/r/user_var.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.37.1.3

  mysql-test/r/view.result@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.138.1.35

  mysql-test/t/func_time.test@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.41.1.13

  mysql-test/t/grant.test@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.41.1.7

  mysql-test/t/im_daemon_life_cycle.imtest@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.1.1.3

  mysql-test/t/im_life_cycle.imtest@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.3.1.5

  mysql-test/t/im_utils.imtest@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.1.1.3

  mysql-test/t/innodb_mysql.test@stripped, 2006-08-30 15:23:57+04:00, anozdrin@stripped +0 -47
    MERGE: 1.3.4.3

  mysql-test/t/join_outer.test@stripped, 2006-08-30 15:23:58+04:00, anozdrin@stripped +7 -0
    MERGE: 1.37.1.1

  mysql-test/t/ps.test@stripped, 2006-08-30 15:24:00+04:00, anozdrin@stripped +1 -30
    MERGE: 1.56.1.13

  mysql-test/t/range.test@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.37.1.4

  mysql-test/t/select.test@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.102.1.10

  mysql-test/t/sp-error.test@stripped, 2006-08-30 14:31:56+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.100.1.8

  mysql-test/t/sp.test@stripped, 2006-08-30 15:24:02+04:00, anozdrin@stripped +0 -86
    MERGE: 1.174.1.24

  mysql-test/t/trigger.test@stripped, 2006-08-30 14:31:57+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.34.1.17

  mysql-test/t/type_datetime.test@stripped, 2006-08-30 14:31:57+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.18.1.1

  mysql-test/t/type_varchar.test@stripped, 2006-08-30 14:31:57+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.8.1.1

  mysql-test/t/view.test@stripped, 2006-08-30 14:31:57+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.126.1.34

  sql/Makefile.am@stripped, 2006-08-30 15:24:03+04:00, anozdrin@stripped +1 -3
    MERGE: 1.103.1.18

  sql/field.cc@stripped, 2006-08-30 15:24:06+04:00, anozdrin@stripped +6 -19
    MERGE: 1.256.1.67

  sql/ha_innodb.cc@stripped, 2006-08-30 14:31:57+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.202.1.96

  sql/item.cc@stripped, 2006-08-30 14:31:57+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.113.1.120

  sql/item.h@stripped, 2006-08-30 14:31:57+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.183.1.24

  sql/item_cmpfunc.cc@stripped, 2006-08-30 15:24:07+04:00, anozdrin@stripped +25 -55
    MERGE: 1.187.1.30

  sql/item_func.cc@stripped, 2006-08-30 14:31:58+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.270.1.30

  sql/item_func.h@stripped, 2006-08-30 14:31:58+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.136.2.11

  sql/item_row.cc@stripped, 2006-08-30 14:31:58+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.32.1.1

  sql/item_strfunc.cc@stripped, 2006-08-30 14:31:58+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.261.1.20

  sql/item_strfunc.h@stripped, 2006-08-30 14:31:58+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.101.1.14

  sql/item_subselect.cc@stripped, 2006-08-30 14:31:58+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.113.1.19

  sql/item_timefunc.cc@stripped, 2006-08-30 14:31:58+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.100.1.24

  sql/mysql_priv.h@stripped, 2006-08-30 15:24:09+04:00, anozdrin@stripped +0 -14
    MERGE: 1.290.1.117

  sql/mysqld.cc@stripped, 2006-08-30 15:24:10+04:00, anozdrin@stripped +2 -1
    MERGE: 1.439.1.129

  sql/net_serv.cc@stripped, 2006-08-30 14:31:59+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.88.1.2

  sql/opt_range.cc@stripped, 2006-08-30 15:24:12+04:00, anozdrin@stripped +125 -229
    MERGE: 1.159.1.63

  sql/opt_range.h@stripped, 2006-08-30 14:31:59+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.57.1.3

  sql/protocol.cc@stripped, 2006-08-30 14:31:59+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.111.1.5

  sql/set_var.cc@stripped, 2006-08-30 14:31:59+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.125.5.20

  sql/share/errmsg.txt@stripped, 2006-08-30 15:24:20+04:00, anozdrin@stripped +0 -6
    MERGE: 1.42.1.27

  sql/sp.cc@stripped, 2006-08-30 15:24:13+04:00, anozdrin@stripped +0 -15
    MERGE: 1.82.1.34

  sql/sp_head.cc@stripped, 2006-08-30 14:31:59+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.200.1.22

  sql/sp_head.h@stripped, 2006-08-30 15:24:14+04:00, anozdrin@stripped +6 -11
    MERGE: 1.79.1.9

  sql/sql_acl.cc@stripped, 2006-08-30 14:31:59+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.128.1.78

  sql/sql_base.cc@stripped, 2006-08-30 15:24:15+04:00, anozdrin@stripped +0 -7
    MERGE: 1.235.1.114

  sql/sql_cache.cc@stripped, 2006-08-30 14:31:59+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.76.1.17

  sql/sql_cache.h@stripped, 2006-08-30 14:31:59+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.30.1.3

  sql/sql_class.cc@stripped, 2006-08-30 14:32:00+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.223.1.24

  sql/sql_delete.cc@stripped, 2006-08-30 14:32:00+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.144.1.34

  sql/sql_error.cc@stripped, 2006-08-30 14:32:00+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.36.1.2

  sql/sql_insert.cc@stripped, 2006-08-30 14:32:00+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.146.1.53

  sql/sql_load.cc@stripped, 2006-08-30 14:32:00+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.78.1.19

  sql/sql_parse.cc@stripped, 2006-08-30 14:32:00+04:00, anozdrin@stripped +1 -0
    Auto merged
    MERGE: 1.426.1.142

  sql/sql_select.cc@stripped, 2006-08-30 14:32:00+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.312.1.136

  sql/sql_trigger.cc@stripped, 2006-08-30 15:24:17+04:00, anozdrin@stripped +61 -58
    MERGE: 1.35.1.20

  sql/sql_trigger.h@stripped, 2006-08-30 14:32:01+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.19.1.2

  sql/sql_update.cc@stripped, 2006-08-30 14:32:01+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.154.2.42

  sql/sql_view.cc@stripped, 2006-08-30 15:24:18+04:00, anozdrin@stripped +22 -30
    MERGE: 1.78.1.15

  sql/sql_yacc.yy@stripped, 2006-08-30 14:32:01+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.371.1.110

  storage/innobase/btr/btr0btr.c@stripped, 2006-08-30 14:32:01+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.38.3.2

  storage/innobase/btr/btr0btr.c@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/btr/btr0btr.c -> storage/innobase/btr/btr0btr.c

  storage/innobase/buf/buf0buf.c@stripped, 2006-08-30 14:32:02+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.45.6.2

  storage/innobase/buf/buf0buf.c@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/buf/buf0buf.c -> storage/innobase/buf/buf0buf.c

  storage/innobase/dict/dict0dict.c@stripped, 2006-08-30 14:32:02+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.65.11.2

  storage/innobase/dict/dict0dict.c@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/dict/dict0dict.c -> storage/innobase/dict/dict0dict.c

  storage/innobase/fil/fil0fil.c@stripped, 2006-08-30 14:32:02+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.54.11.2

  storage/innobase/fil/fil0fil.c@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/fil/fil0fil.c -> storage/innobase/fil/fil0fil.c

  storage/innobase/fsp/fsp0fsp.c@stripped, 2006-08-30 14:32:02+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.25.2.2

  storage/innobase/fsp/fsp0fsp.c@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/fsp/fsp0fsp.c -> storage/innobase/fsp/fsp0fsp.c

  storage/innobase/include/btr0cur.ic@stripped, 2006-08-30 15:24:23+04:00, anozdrin@stripped +4 -1
    MERGE: 1.2.2.2

  storage/innobase/include/btr0cur.ic@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/include/btr0cur.ic -> storage/innobase/include/btr0cur.ic

  storage/innobase/include/buf0buf.ic@stripped, 2006-08-30 14:32:02+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.17.2.2

  storage/innobase/include/buf0buf.ic@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/include/buf0buf.ic -> storage/innobase/include/buf0buf.ic

  storage/innobase/log/log0log.c@stripped, 2006-08-30 14:32:02+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.41.4.2

  storage/innobase/log/log0log.c@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/log/log0log.c -> storage/innobase/log/log0log.c

  storage/innobase/log/log0recv.c@stripped, 2006-08-30 14:32:02+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.46.5.2

  storage/innobase/log/log0recv.c@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/log/log0recv.c -> storage/innobase/log/log0recv.c

  storage/innobase/os/os0file.c@stripped, 2006-08-30 14:32:02+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.103.10.2

  storage/innobase/os/os0file.c@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/os/os0file.c -> storage/innobase/os/os0file.c

  storage/innobase/row/row0mysql.c@stripped, 2006-08-30 15:24:24+04:00, anozdrin@stripped +13 -13
    MERGE: 1.103.15.2

  storage/innobase/row/row0mysql.c@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/row/row0mysql.c -> storage/innobase/row/row0mysql.c

  storage/innobase/row/row0sel.c@stripped, 2006-08-30 14:32:02+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.92.8.2

  storage/innobase/row/row0sel.c@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/row/row0sel.c -> storage/innobase/row/row0sel.c

  storage/innobase/srv/srv0start.c@stripped, 2006-08-30 14:32:02+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.80.10.2

  storage/innobase/srv/srv0start.c@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/srv/srv0start.c -> storage/innobase/srv/srv0start.c

  storage/innobase/ut/ut0dbg.c@stripped, 2006-08-30 14:32:02+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.7.2.2

  storage/innobase/ut/ut0dbg.c@stripped, 2006-08-30 14:31:55+04:00, anozdrin@stripped +0 -0
    Merge rename: innobase/ut/ut0dbg.c -> storage/innobase/ut/ut0dbg.c

  tests/mysql_client_test.c@stripped, 2006-08-30 14:32:02+04:00, anozdrin@stripped +0 -0
    Auto merged
    MERGE: 1.167.1.37

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	anozdrin
# Host:	booka.site
# Root:	/home/alik/MySQL/devel/5.1-rt-merged/RESYNC

--- 1.109/include/mysql_com.h	2006-08-30 15:25:37 +04:00
+++ 1.110/include/mysql_com.h	2006-08-30 15:25:37 +04:00
@@ -213,7 +213,13 @@ typedef struct st_net {
   char last_error[MYSQL_ERRMSG_SIZE], sqlstate[SQLSTATE_LENGTH+1];
   unsigned int last_errno;
   unsigned char error;
+
+  /*
+    'query_cache_query' should be accessed only via query cache
+    functions and methods to maintain proper locking.
+  */
   gptr query_cache_query;
+
   my_bool report_error; /* We should report error (we have unreported error) */
   my_bool return_errno;
 } NET;

--- 1.205/sql/item.cc	2006-08-30 15:25:37 +04:00
+++ 1.206/sql/item.cc	2006-08-30 15:25:37 +04:00
@@ -302,6 +302,7 @@ Item::Item():
   maybe_null=null_value=with_sum_func=unsigned_flag=0;
   decimals= 0; max_length= 0;
   with_subselect= 0;
+  cmp_context= (Item_result)-1;
 
   /* Put item in free list so that we can free all items at end */
   THD *thd= current_thd;
@@ -340,7 +341,8 @@ Item::Item(THD *thd, Item *item):
   unsigned_flag(item->unsigned_flag),
   with_sum_func(item->with_sum_func),
   fixed(item->fixed),
-  collation(item->collation)
+  collation(item->collation),
+  cmp_context(item->cmp_context)
 {
   next= thd->free_list;				// Put in free list
   thd->free_list= this;
@@ -417,6 +419,49 @@ void Item::rename(char *new_name)
 }
 
 
+/*
+  Traverse item tree possibly transforming it (replacing items).
+
+  SYNOPSIS
+    Item::transform()
+      transformer    functor that performs transformation of a subtree
+      arg            opaque argument passed to the functor
+
+  DESCRIPTION
+    This function is designed to ease transformation of Item trees.
+
+    Re-execution note: every such transformation is registered for
+    rollback by THD::change_item_tree() and is rolled back at the end
+    of execution by THD::rollback_item_tree_changes().
+
+    Therefore:
+
+      - this function can not be used at prepared statement prepare
+        (in particular, in fix_fields!), as only permanent
+        transformation of Item trees are allowed at prepare.
+
+      - the transformer function shall allocate new Items in execution
+        memory root (thd->mem_root) and not anywhere else: allocated
+        items will be gone in the end of execution.
+
+    If you don't need to transform an item tree, but only traverse
+    it, please use Item::walk() instead.
+
+
+  RETURN VALUE
+    Returns pointer to the new subtree root.  THD::change_item_tree()
+    should be called for it if transformation took place, i.e. if a
+    pointer to newly allocated item is returned.
+*/
+
+Item* Item::transform(Item_transformer transformer, byte *arg)
+{
+  DBUG_ASSERT(!current_thd->is_stmt_prepare());
+
+  return (this->*transformer)(arg);
+}
+
+
 Item_ident::Item_ident(Name_resolution_context *context_arg,
                        const char *db_name_arg,const char *table_name_arg,
 		       const char *field_name_arg)
@@ -3828,7 +3873,19 @@ Item *Item_field::equal_fields_propagato
   Item *item= 0;
   if (item_equal)
     item= item_equal->get_const();
-  if (!item)
+  /*
+    Disable const propagation for items used in different comparison contexts.
+    This must be done because, for example, Item_hex_string->val_int() is not
+    the same as (Item_hex_string->val_str() in BINARY column)->val_int().
+    We cannot simply disable the replacement in a particular context (
+    e.g. <bin_col> = <int_col> AND <bin_col> = <hex_string>) since
+    Items don't know the context they are in and there are functions like 
+    IF (<hex_string>, 'yes', 'no').
+    The same problem occurs when comparing a DATE/TIME field with a
+    DATE/TIME represented as an int and as a string.
+  */
+  if (!item ||
+      (cmp_context != (Item_result)-1 && item->cmp_context != cmp_context))
     item= this;
   return item;
 }
@@ -3839,11 +3896,11 @@ Item *Item_field::equal_fields_propagato
   See comments in Arg_comparator::set_compare_func() for details
 */
 
-Item *Item_field::set_no_const_sub(byte *arg)
+bool Item_field::set_no_const_sub(byte *arg)
 {
   if (field->charset() != &my_charset_bin)
     no_const_subst=1;
-  return this;
+  return FALSE;
 }
 
 
@@ -5373,6 +5430,31 @@ int Item_default_value::save_in_field(Fi
     return 0;
   }
   return Item_field::save_in_field(field_arg, no_conversions);
+}
+
+
+/* 
+  This method like the walk method traverses the item tree, but at the
+  same time it can replace some nodes in the tree
+*/ 
+
+Item *Item_default_value::transform(Item_transformer transformer, byte *args)
+{
+  DBUG_ASSERT(!current_thd->is_stmt_prepare());
+
+  Item *new_item= arg->transform(transformer, args);
+  if (!new_item)
+    return 0;
+
+  /*
+    THD::change_item_tree() should be called only if the tree was
+    really transformed, i.e. when a new item has been created.
+    Otherwise we'll be allocating a lot of unnecessary memory for
+    change records at each execution.
+  */
+  if (arg != new_item)
+    current_thd->change_item_tree(&arg, new_item);
+  return (this->*transformer)(args);
 }
 
 

--- 1.207/sql/item.h	2006-08-30 15:25:37 +04:00
+++ 1.208/sql/item.h	2006-08-30 15:25:37 +04:00
@@ -495,7 +495,7 @@ public:
   my_bool with_subselect;               /* If this item is a subselect or some
                                            of its arguments is or contains a
                                            subselect */
-
+  Item_result cmp_context;              /* Comparison context */
   // alloc & destruct is done as start of select using sql_alloc
   Item();
   /*
@@ -774,10 +774,7 @@ public:
     return (this->*processor)(arg);
   }
 
-  virtual Item* transform(Item_transformer transformer, byte *arg)
-  {
-    return (this->*transformer)(arg);
-  }
+  virtual Item* transform(Item_transformer transformer, byte *arg);
 
    virtual void traverse_cond(Cond_traverser traverser,
                               void *arg, traverse_order order)
@@ -818,7 +815,7 @@ public:
   { *(bool *)bool_arg= FALSE; return 0; }
 
   virtual Item *equal_fields_propagator(byte * arg) { return this; }
-  virtual Item *set_no_const_sub(byte *arg) { return this; }
+  virtual bool set_no_const_sub(byte *arg) { return FALSE; }
   virtual Item *replace_equal_field(byte * arg) { return this; }
 
   /*
@@ -1319,7 +1316,7 @@ public:
   }
   Item_equal *find_item_equal(COND_EQUAL *cond_equal);
   Item *equal_fields_propagator(byte *arg);
-  Item *set_no_const_sub(byte *arg);
+  bool set_no_const_sub(byte *arg);
   Item *replace_equal_field(byte *arg);
   inline uint32 max_disp_length() { return field->max_length(); }
   Item_field *filed_for_view_update() { return this; }
@@ -2197,18 +2194,7 @@ public:
       (this->*processor)(args);
   }
 
-  /* 
-     This method like the walk method traverses the item tree, but
-     at the same time it can replace some nodes in the tree
-  */ 
-  Item *transform(Item_transformer transformer, byte *args)
-  {
-    Item *new_item= arg->transform(transformer, args);
-    if (!new_item)
-      return 0;
-    arg= new_item;
-    return (this->*transformer)(args);
-  }
+  Item *transform(Item_transformer transformer, byte *args);
 };
 
 /*

--- 1.308/sql/item_func.cc	2006-08-30 15:25:37 +04:00
+++ 1.309/sql/item_func.cc	2006-08-30 15:25:37 +04:00
@@ -260,6 +260,8 @@ void Item_func::traverse_cond(Cond_trave
 
 Item *Item_func::transform(Item_transformer transformer, byte *argument)
 {
+  DBUG_ASSERT(!current_thd->is_stmt_prepare());
+
   if (arg_count)
   {
     Item **arg,**arg_end;
@@ -268,6 +270,13 @@ Item *Item_func::transform(Item_transfor
       Item *new_item= (*arg)->transform(transformer, argument);
       if (!new_item)
 	return 0;
+
+      /*
+        THD::change_item_tree() should be called only if the tree was
+        really transformed, i.e. when a new item has been created.
+        Otherwise we'll be allocating a lot of unnecessary memory for
+        change records at each execution.
+      */
       if (*arg != new_item)
         current_thd->change_item_tree(arg, new_item);
     }
@@ -551,7 +560,7 @@ void Item_func::signal_divide_by_null()
 
 Item *Item_func::get_tmp_table_item(THD *thd)
 {
-  if (!with_sum_func && !const_item())
+  if (!with_sum_func && !const_item() && functype() != SUSERVAR_FUNC)
     return new Item_field(result_field);
   return copy_or_same(thd);
 }
@@ -3741,30 +3750,38 @@ my_decimal *user_var_entry::val_decimal(
 */
 
 bool
-Item_func_set_user_var::check()
+Item_func_set_user_var::check(bool use_result_field)
 {
   DBUG_ENTER("Item_func_set_user_var::check");
+  if (use_result_field)
+    DBUG_ASSERT(result_field);
 
   switch (cached_result_type) {
   case REAL_RESULT:
   {
-    save_result.vreal= args[0]->val_real();
+    save_result.vreal= use_result_field ? result_field->val_real() :
+                        args[0]->val_real();
     break;
   }
   case INT_RESULT:
   {
-    save_result.vint= args[0]->val_int();
-    unsigned_flag= args[0]->unsigned_flag;
+    save_result.vint= use_result_field ? result_field->val_int() :
+                       args[0]->val_int();
+    unsigned_flag= use_result_field ? ((Field_num*)result_field)->unsigned_flag:
+                    args[0]->unsigned_flag;
     break;
   }
   case STRING_RESULT:
   {
-    save_result.vstr= args[0]->val_str(&value);
+    save_result.vstr= use_result_field ? result_field->val_str(&value) :
+                       args[0]->val_str(&value);
     break;
   }
   case DECIMAL_RESULT:
   {
-    save_result.vdec= args[0]->val_decimal(&decimal_buff);
+    save_result.vdec= use_result_field ?
+                       result_field->val_decimal(&decimal_buff) :
+                       args[0]->val_decimal(&decimal_buff);
     break;
   }
   case ROW_RESULT:
@@ -3850,7 +3867,7 @@ Item_func_set_user_var::update()
 double Item_func_set_user_var::val_real()
 {
   DBUG_ASSERT(fixed == 1);
-  check();
+  check(0);
   update();					// Store expression
   return entry->val_real(&null_value);
 }
@@ -3858,7 +3875,7 @@ double Item_func_set_user_var::val_real(
 longlong Item_func_set_user_var::val_int()
 {
   DBUG_ASSERT(fixed == 1);
-  check();
+  check(0);
   update();					// Store expression
   return entry->val_int(&null_value);
 }
@@ -3866,7 +3883,7 @@ longlong Item_func_set_user_var::val_int
 String *Item_func_set_user_var::val_str(String *str)
 {
   DBUG_ASSERT(fixed == 1);
-  check();
+  check(0);
   update();					// Store expression
   return entry->val_str(&null_value, str, decimals);
 }
@@ -3875,7 +3892,7 @@ String *Item_func_set_user_var::val_str(
 my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val)
 {
   DBUG_ASSERT(fixed == 1);
-  check();
+  check(0);
   update();					// Store expression
   return entry->val_decimal(&null_value, val);
 }
@@ -3900,6 +3917,29 @@ void Item_func_set_user_var::print_as_st
   str->append(')');
 }
 
+bool Item_func_set_user_var::send(Protocol *protocol, String *str_arg)
+{
+  if (result_field)
+  {
+    check(1);
+    update();
+    return protocol->store(result_field);
+  }
+  return Item::send(protocol, str_arg);
+}
+
+void Item_func_set_user_var::make_field(Send_field *tmp_field)
+{
+  if (result_field)
+  {
+    result_field->make_field(tmp_field);
+    DBUG_ASSERT(tmp_field->table_name != 0);
+    if (Item::name)
+      tmp_field->col_name=Item::name;               // Use user supplied name
+  }
+  else
+    Item::make_field(tmp_field);
+}
 
 String *
 Item_func_get_user_var::val_str(String *str)
@@ -4165,7 +4205,7 @@ bool Item_func_get_user_var::set_value(T
     Item_func_set_user_var is not fixed after construction, call
     fix_fields().
   */
-  return (!suv || suv->fix_fields(thd, it) || suv->check() || suv->update());
+  return (!suv || suv->fix_fields(thd, it) || suv->check(0) || suv->update());
 }
 
 

--- 1.144/sql/item_func.h	2006-08-30 15:25:37 +04:00
+++ 1.145/sql/item_func.h	2006-08-30 15:25:37 +04:00
@@ -54,7 +54,7 @@ public:
 		  SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN,
                   NOT_FUNC, NOT_ALL_FUNC,
                   NOW_FUNC, TRIG_COND_FUNC,
-                  GUSERVAR_FUNC, COLLATE_FUNC,
+                  SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC,
                   EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC };
   enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL,
                        OPTIMIZE_EQUAL };
@@ -1196,13 +1196,16 @@ public:
   Item_func_set_user_var(LEX_STRING a,Item *b)
     :Item_func(b), cached_result_type(INT_RESULT), name(a)
   {}
+  enum Functype functype() const { return SUSERVAR_FUNC; }
   double val_real();
   longlong val_int();
   String *val_str(String *str);
   my_decimal *val_decimal(my_decimal *);
   bool update_hash(void *ptr, uint length, enum Item_result type,
   		   CHARSET_INFO *cs, Derivation dv, bool unsigned_arg= 0);
-  bool check();
+  bool send(Protocol *protocol, String *str_arg);
+  void make_field(Send_field *tmp_field);
+  bool check(bool use_result_field);
   bool update();
   enum Item_result result_type () const { return cached_result_type; }
   bool fix_fields(THD *thd, Item **ref);

--- 1.285/sql/item_strfunc.cc	2006-08-30 15:25:38 +04:00
+++ 1.286/sql/item_strfunc.cc	2006-08-30 15:25:38 +04:00
@@ -2051,6 +2051,26 @@ String *Item_func_make_set::val_str(Stri
 }
 
 
+Item *Item_func_make_set::transform(Item_transformer transformer, byte *arg)
+{
+  DBUG_ASSERT(!current_thd->is_stmt_prepare());
+
+  Item *new_item= item->transform(transformer, arg);
+  if (!new_item)
+    return 0;
+
+  /*
+    THD::change_item_tree() should be called only if the tree was
+    really transformed, i.e. when a new item has been created.
+    Otherwise we'll be allocating a lot of unnecessary memory for
+    change records at each execution.
+  */
+  if (item != new_item)
+    current_thd->change_item_tree(&item, new_item);
+  return Item_str_func::transform(transformer, arg);
+}
+
+
 void Item_func_make_set::print(String *str)
 {
   str->append(STRING_WITH_LEN("make_set("));

--- 1.116/sql/item_strfunc.h	2006-08-30 15:25:38 +04:00
+++ 1.117/sql/item_strfunc.h	2006-08-30 15:25:38 +04:00
@@ -484,14 +484,7 @@ public:
     return item->walk(processor, walk_subquery, arg) ||
       Item_str_func::walk(processor, walk_subquery, arg);
   }
-  Item *transform(Item_transformer transformer, byte *arg)
-  {
-    Item *new_item= item->transform(transformer, arg);
-    if (!new_item)
-      return 0;
-    item= new_item;
-    return Item_str_func::transform(transformer, arg);
-  }
+  Item *transform(Item_transformer transformer, byte *arg);
   void print(String *str);
 };
 

--- 1.131/sql/item_timefunc.cc	2006-08-30 15:25:38 +04:00
+++ 1.132/sql/item_timefunc.cc	2006-08-30 15:25:38 +04:00
@@ -224,7 +224,7 @@ static bool extract_date_time(DATE_TIME_
 	tmp= (char*) val + min(2, val_len);
 	l_time->day= (int) my_strtoll10(val, &tmp, &error);
 	/* Skip 'st, 'nd, 'th .. */
-	val= tmp + min((int) (end-tmp), 2);
+	val= tmp + min((int) (val_end-tmp), 2);
 	break;
 
 	/* Hour */

--- 1.117/sql/protocol.cc	2006-08-30 15:25:38 +04:00
+++ 1.118/sql/protocol.cc	2006-08-30 15:25:38 +04:00
@@ -53,8 +53,18 @@ bool Protocol_prep::net_store_data(const
 }
 
 
-	/* Send a error string to client */
+/*
+   Send a error string to client
+
+   Design note:
 
+   net_printf_error and net_send_error are low-level functions
+   that shall be used only when a new connection is being
+   established or at server startup.
+   For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
+   critical that every error that can be intercepted is issued in one
+   place only, my_message_sql.
+*/
 void net_send_error(THD *thd, uint sql_errno, const char *err)
 {
   NET *net= &thd->net;
@@ -64,19 +74,15 @@ void net_send_error(THD *thd, uint sql_e
 		      err ? err : net->last_error[0] ?
 		      net->last_error : "NULL"));
 
+  DBUG_ASSERT(!thd->spcont);
+
   if (net && net->no_send_error)
   {
     thd->clear_error();
     DBUG_PRINT("info", ("sending error messages prohibited"));
     DBUG_VOID_RETURN;
   }
-  if (thd->spcont && thd->spcont->find_handler(sql_errno,
-                                               MYSQL_ERROR::WARN_LEVEL_ERROR))
-  {
-    if (! thd->spcont->found_handler_here())
-      thd->net.report_error= 1; /* Make "select" abort correctly */ 
-    DBUG_VOID_RETURN;
-  }
+
   thd->query_error=  1; // needed to catch query errors during replication
   if (!err)
   {
@@ -117,6 +123,15 @@ void net_send_error(THD *thd, uint sql_e
    Write error package and flush to client
    It's a little too low level, but I don't want to use another buffer for
    this
+
+   Design note:
+
+   net_printf_error and net_send_error are low-level functions
+   that shall be used only when a new connection is being
+   established or at server startup.
+   For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
+   critical that every error that can be intercepted is issued in one
+   place only, my_message_sql.
 */
 
 void
@@ -136,6 +151,8 @@ net_printf_error(THD *thd, uint errcode,
   DBUG_ENTER("net_printf_error");
   DBUG_PRINT("enter",("message: %u",errcode));
 
+  DBUG_ASSERT(!thd->spcont);
+
   if (net && net->no_send_error)
   {
     thd->clear_error();
@@ -143,13 +160,6 @@ net_printf_error(THD *thd, uint errcode,
     DBUG_VOID_RETURN;
   }
 
-  if (thd->spcont && thd->spcont->find_handler(errcode,
-                                               MYSQL_ERROR::WARN_LEVEL_ERROR))
-  {
-    if (! thd->spcont->found_handler_here())
-      thd->net.report_error= 1; /* Make "select" abort correctly */ 
-    DBUG_VOID_RETURN;
-  }
   thd->query_error=  1; // needed to catch query errors during replication
 #ifndef EMBEDDED_LIBRARY
   query_cache_abort(net);	// Safety

--- 1.92/sql/net_serv.cc	2006-08-30 15:25:38 +04:00
+++ 1.93/sql/net_serv.cc	2006-08-30 15:25:38 +04:00
@@ -95,8 +95,11 @@ extern uint test_flags;
 extern ulong bytes_sent, bytes_received, net_big_packet_count;
 extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
 #ifndef MYSQL_INSTANCE_MANAGER
-extern void query_cache_insert(NET *net, const char *packet, ulong length);
+#ifdef HAVE_QUERY_CACHE
 #define USE_QUERY_CACHE
+extern void query_cache_init_query(NET *net);
+extern void query_cache_insert(NET *net, const char *packet, ulong length);
+#endif // HAVE_QUERY_CACHE
 #define update_statistics(A) A
 #endif /* MYSQL_INSTANCE_MANGER */
 #endif /* defined(MYSQL_SERVER) && !defined(MYSQL_INSTANCE_MANAGER) */
@@ -132,7 +135,11 @@ my_bool my_net_init(NET *net, Vio* vio)
   net->compress=0; net->reading_or_writing=0;
   net->where_b = net->remain_in_buf=0;
   net->last_errno=0;
-  net->query_cache_query=0;
+#ifdef USE_QUERY_CACHE
+  query_cache_init_query(net);
+#else
+  net->query_cache_query= 0;
+#endif
   net->report_error= 0;
 
   if (vio != 0)					/* If real connection */
@@ -551,10 +558,8 @@ net_real_write(NET *net,const char *pack
   my_bool net_blocking = vio_is_blocking(net->vio);
   DBUG_ENTER("net_real_write");
 
-#if defined(MYSQL_SERVER) && defined(HAVE_QUERY_CACHE) \
-                          && !defined(MYSQL_INSTANCE_MANAGER)
-  if (net->query_cache_query != 0)
-    query_cache_insert(net, packet, len);
+#if defined(MYSQL_SERVER) && defined(USE_QUERY_CACHE)
+  query_cache_insert(net, packet, len);
 #endif
 
   if (net->error == 2)

--- 1.207/sql/sql_acl.cc	2006-08-30 15:25:38 +04:00
+++ 1.208/sql/sql_acl.cc	2006-08-30 15:25:38 +04:00
@@ -1006,6 +1006,7 @@ int acl_getroot(THD *thd, USER_RESOURCES
             sql_print_information("X509 issuer mismatch: should be '%s' "
 			      "but is '%s'", acl_user->x509_issuer, ptr);
           free(ptr);
+          user_access=NO_ACCESS;
           break;
         }
         user_access= acl_user->access;
@@ -1021,11 +1022,13 @@ int acl_getroot(THD *thd, USER_RESOURCES
         if (strcmp(acl_user->x509_subject,ptr))
         {
           if (global_system_variables.log_warnings)
-            sql_print_information("X509 subject mismatch: '%s' vs '%s'",
+            sql_print_information("X509 subject mismatch: should be '%s' but is '%s'",
                             acl_user->x509_subject, ptr);
+          free(ptr);
+          user_access=NO_ACCESS;
+          break;
         }
-        else
-          user_access= acl_user->access;
+        user_access= acl_user->access;
         free(ptr);
       }
       break;
@@ -3041,14 +3044,6 @@ bool mysql_table_grant(THD *thd, TABLE_L
       result= TRUE;
       continue;
     }  
-    if (Str->host.length > HOSTNAME_LENGTH ||
-	Str->user.length > USERNAME_LENGTH)
-    {
-      my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
-                 MYF(0));
-      result= TRUE;
-      continue;
-    }
     /* Create user if needed */
     error=replace_user_table(thd, tables[0].table, *Str,
 			     0, revoke_grant, create_new_users,
@@ -3253,15 +3248,6 @@ bool mysql_routine_grant(THD *thd, TABLE
       result= TRUE;
       continue;
     }  
-    if (Str->host.length > HOSTNAME_LENGTH ||
-	Str->user.length > USERNAME_LENGTH)
-    {
-      if (!no_error)
-	my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
-                   MYF(0));
-      result= TRUE;
-      continue;
-    }
     /* Create user if needed */
     error=replace_user_table(thd, tables[0].table, *Str,
 			     0, revoke_grant, create_new_users,
@@ -3387,14 +3373,6 @@ bool mysql_grant(THD *thd, const char *d
       result= TRUE;
       continue;
     }  
-    if (Str->host.length > HOSTNAME_LENGTH ||
-	Str->user.length > USERNAME_LENGTH)
-    {
-      my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
-                 MYF(0));
-      result= -1;
-      continue;
-    }
     if (replace_user_table(thd, tables[0].table, *Str,
                            (!db ? rights : 0), revoke_grant, create_new_users,
                            test(thd->variables.sql_mode &
@@ -4304,14 +4282,6 @@ bool mysql_show_grants(THD *thd,LEX_USER
     DBUG_RETURN(TRUE);
   }
 
-  if (lex_user->host.length > HOSTNAME_LENGTH ||
-      lex_user->user.length > USERNAME_LENGTH)
-  {
-    my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
-               MYF(0));
-    DBUG_RETURN(TRUE);
-  }
-
   rw_rdlock(&LOCK_grant);
   VOID(pthread_mutex_lock(&acl_cache->lock));
 
@@ -5405,14 +5375,6 @@ bool mysql_create_user(THD *thd, List <L
   {
     if (!(user_name= get_current_user(thd, tmp_user_name)))
     {
-      result= TRUE;
-      continue;
-    }
-
-    if (user_name->host.length > HOSTNAME_LENGTH ||
-	user_name->user.length > USERNAME_LENGTH)
-    {
-      append_user(&wrong_users, user_name);
       result= TRUE;
       continue;
     }

--- 1.94/sql/sql_cache.cc	2006-08-30 15:25:38 +04:00
+++ 1.95/sql/sql_cache.cc	2006-08-30 15:25:38 +04:00
@@ -565,21 +565,62 @@ byte *query_cache_query_get_key(const by
 *****************************************************************************/
 
 /*
+  Note on double-check locking (DCL) usage.
+
+  Below, in query_cache_insert(), query_cache_abort() and
+  query_cache_end_of_result() we use what is called double-check
+  locking (DCL) for NET::query_cache_query.  I.e. we test it first
+  without a lock, and, if positive, test again under the lock.
+
+  This means that if we see 'NET::query_cache_query == 0' without a
+  lock we will skip the operation.  But this is safe here: when we
+  started to cache a query, we called Query_cache::store_query(), and
+  NET::query_cache_query was set to non-zero in this thread (and the
+  thread always sees results of its memory operations, mutex or not).
+  If later we see 'NET::query_cache_query == 0' without locking a
+  mutex, that may only mean that some other thread have reset it by
+  invalidating the query.  Skipping the operation in this case is the
+  right thing to do, as NET::query_cache_query won't get non-zero for
+  this query again.
+
+  See also comments in Query_cache::store_query() and
+  Query_cache::send_result_to_client().
+
+  NOTE, however, that double-check locking is not applicable in
+  'invalidate' functions, as we may erroneously skip invalidation,
+  because the thread doing invalidation may never see non-zero
+  NET::query_cache_query.
+*/
+
+
+void query_cache_init_query(NET *net)
+{
+  /*
+    It is safe to initialize 'NET::query_cache_query' without a lock
+    here, because before it will be accessed from different threads it
+    will be set in this thread under a lock, and access from the same
+    thread is always safe.
+  */
+  net->query_cache_query= 0;
+}
+
+
+/*
   Insert the packet into the query cache.
-  This should only be called if net->query_cache_query != 0
 */
 
 void query_cache_insert(NET *net, const char *packet, ulong length)
 {
   DBUG_ENTER("query_cache_insert");
 
+  /* See the comment on double-check locking usage above. */
+  if (net->query_cache_query == 0)
+    DBUG_VOID_RETURN;
+
   STRUCT_LOCK(&query_cache.structure_guard_mutex);
-  /*
-    It is very unlikely that following condition is TRUE (it is possible
-    only if other thread is resizing cache), so we check it only after guard
-    mutex lock
-  */
-  if (unlikely(query_cache.query_cache_size == 0))
+
+  if (unlikely(query_cache.query_cache_size == 0 ||
+               query_cache.flush_in_progress))
   {
     STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
     DBUG_VOID_RETURN;
@@ -616,10 +657,10 @@ void query_cache_insert(NET *net, const 
     header->result(result);
     header->last_pkt_nr= net->pkt_nr;
     BLOCK_UNLOCK_WR(query_block);
+    DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
   }
   else
     STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
-  DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
   DBUG_VOID_RETURN;
 }
 
@@ -628,33 +669,33 @@ void query_cache_abort(NET *net)
 {
   DBUG_ENTER("query_cache_abort");
 
-  if (net->query_cache_query != 0)	// Quick check on unlocked structure
+  /* See the comment on double-check locking usage above. */
+  if (net->query_cache_query == 0)
+    DBUG_VOID_RETURN;
+
+  STRUCT_LOCK(&query_cache.structure_guard_mutex);
+
+  if (unlikely(query_cache.query_cache_size == 0 ||
+               query_cache.flush_in_progress))
   {
-    STRUCT_LOCK(&query_cache.structure_guard_mutex);
-    /*
-      It is very unlikely that following condition is TRUE (it is possible
-      only if other thread is resizing cache), so we check it only after guard
-      mutex lock
-    */
-    if (unlikely(query_cache.query_cache_size == 0))
-    {
-      STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
-      DBUG_VOID_RETURN;
-    }
+    STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+    DBUG_VOID_RETURN;
+  }
 
-    Query_cache_block *query_block = ((Query_cache_block*)
-				       net->query_cache_query);
-    if (query_block)			// Test if changed by other thread
-    {
-      DUMP(&query_cache);
-      BLOCK_LOCK_WR(query_block);
-      // The following call will remove the lock on query_block
-      query_cache.free_query(query_block);
-    }
-    net->query_cache_query=0;
+  Query_cache_block *query_block= ((Query_cache_block*)
+                                   net->query_cache_query);
+  if (query_block)			// Test if changed by other thread
+  {
+    DUMP(&query_cache);
+    BLOCK_LOCK_WR(query_block);
+    // The following call will remove the lock on query_block
+    query_cache.free_query(query_block);
+    net->query_cache_query= 0;
     DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
-    STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
   }
+
+  STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+
   DBUG_VOID_RETURN;
 }
 
@@ -663,60 +704,65 @@ void query_cache_end_of_result(THD *thd)
 {
   DBUG_ENTER("query_cache_end_of_result");
 
-  if (thd->net.query_cache_query != 0)	// Quick check on unlocked structure
-  {
+  /* See the comment on double-check locking usage above. */
+  if (thd->net.query_cache_query == 0)
+    DBUG_VOID_RETURN;
+
 #ifdef EMBEDDED_LIBRARY
-    query_cache_insert(&thd->net, (char*)thd, 
-		       emb_count_querycache_size(thd));
+  query_cache_insert(&thd->net, (char*)thd, 
+                     emb_count_querycache_size(thd));
 #endif
-    STRUCT_LOCK(&query_cache.structure_guard_mutex);
-    /*
-      It is very unlikely that following condition is TRUE (it is possible
-      only if other thread is resizing cache), so we check it only after guard
-      mutex lock
-    */
-    if (unlikely(query_cache.query_cache_size == 0))
-    {
-      STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
-      DBUG_VOID_RETURN;
-    }
 
-    Query_cache_block *query_block = ((Query_cache_block*)
-				      thd->net.query_cache_query);
-    if (query_block)
-    {
-      DUMP(&query_cache);
-      BLOCK_LOCK_WR(query_block);
-      Query_cache_query *header = query_block->query();
-      Query_cache_block *last_result_block = header->result()->prev;
-      ulong allign_size = ALIGN_SIZE(last_result_block->used);
-      ulong len = max(query_cache.min_allocation_unit, allign_size);
-      if (last_result_block->length >= query_cache.min_allocation_unit + len)
-	query_cache.split_block(last_result_block,len);
-      STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+  STRUCT_LOCK(&query_cache.structure_guard_mutex);
+
+  if (unlikely(query_cache.query_cache_size == 0 ||
+               query_cache.flush_in_progress))
+  {
+    STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+    DBUG_VOID_RETURN;
+  }
+
+  Query_cache_block *query_block= ((Query_cache_block*)
+                                   thd->net.query_cache_query);
+  if (query_block)
+  {
+    DUMP(&query_cache);
+    BLOCK_LOCK_WR(query_block);
+    Query_cache_query *header= query_block->query();
+    Query_cache_block *last_result_block= header->result()->prev;
+    ulong allign_size= ALIGN_SIZE(last_result_block->used);
+    ulong len= max(query_cache.min_allocation_unit, allign_size);
+    if (last_result_block->length >= query_cache.min_allocation_unit + len)
+      query_cache.split_block(last_result_block,len);
 
 #ifndef DBUG_OFF
-      if (header->result() == 0)
-      {
-	DBUG_PRINT("error", ("end of data whith no result. query '%s'",
-			     header->query()));
-	query_cache.wreck(__LINE__, "");
-	DBUG_VOID_RETURN;
-      }
-#endif
-      header->found_rows(current_thd->limit_found_rows);
-      header->result()->type = Query_cache_block::RESULT;
-      header->writer(0);
-      BLOCK_UNLOCK_WR(query_block);
-    }
-    else
+    if (header->result() == 0)
     {
-      // Cache was flushed or resized and query was deleted => do nothing
+      DBUG_PRINT("error", ("end of data whith no result. query '%s'",
+                           header->query()));
+      query_cache.wreck(__LINE__, "");
+
       STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+
+      DBUG_VOID_RETURN;
     }
-    thd->net.query_cache_query=0;
-    DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
+#endif
+    header->found_rows(current_thd->limit_found_rows);
+    header->result()->type= Query_cache_block::RESULT;
+    header->writer(0);
+    thd->net.query_cache_query= 0;
+    DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
+
+    STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+
+    BLOCK_UNLOCK_WR(query_block);
+  }
+  else
+  {
+    // Cache was flushed or resized and query was deleted => do nothing
+    STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
   }
+
   DBUG_VOID_RETURN;
 }
 
@@ -762,8 +808,7 @@ ulong Query_cache::resize(ulong query_ca
 			query_cache_size_arg));
   DBUG_ASSERT(initialized);
   STRUCT_LOCK(&structure_guard_mutex);
-  if (query_cache_size > 0)
-    free_cache();
+  free_cache();
   query_cache_size= query_cache_size_arg;
   ::query_cache_size= init_cache();
   STRUCT_UNLOCK(&structure_guard_mutex);
@@ -784,7 +829,15 @@ void Query_cache::store_query(THD *thd, 
   TABLE_COUNTER_TYPE local_tables;
   ulong tot_length;
   DBUG_ENTER("Query_cache::store_query");
-  if (query_cache_size == 0 || thd->locked_tables)
+  /*
+    Testing 'query_cache_size' without a lock here is safe: the thing
+    we may loose is that the query won't be cached, but we save on
+    mutex locking in the case when query cache is disabled or the
+    query is uncachable.
+
+    See also a note on double-check locking usage above.
+  */
+  if (thd->locked_tables || query_cache_size == 0)
     DBUG_VOID_RETURN;
   uint8 tables_type= 0;
 
@@ -836,9 +889,9 @@ sql mode: 0x%lx, sort len: %lu, conncat 
      acquiring the query cache mutex.
     */
     ha_release_temporary_latches(thd);
-    STRUCT_LOCK(&structure_guard_mutex);
 
-    if (query_cache_size == 0)
+    STRUCT_LOCK(&structure_guard_mutex);
+    if (query_cache_size == 0 || flush_in_progress)
     {
       STRUCT_UNLOCK(&structure_guard_mutex);
       DBUG_VOID_RETURN;
@@ -912,11 +965,12 @@ sql mode: 0x%lx, sort len: %lu, conncat 
 	double_linked_list_simple_include(query_block, &queries_blocks);
 	inserts++;
 	queries_in_cache++;
-	STRUCT_UNLOCK(&structure_guard_mutex);
-
 	net->query_cache_query= (gptr) query_block;
 	header->writer(net);
 	header->tables_type(tables_type);
+
+	STRUCT_UNLOCK(&structure_guard_mutex);
+
 	// init_n_lock make query block locked
 	BLOCK_UNLOCK_WR(query_block);
       }
@@ -970,12 +1024,16 @@ Query_cache::send_result_to_client(THD *
   Query_cache_query_flags flags;
   DBUG_ENTER("Query_cache::send_result_to_client");
 
-  if (query_cache_size == 0 || thd->locked_tables ||
-      thd->variables.query_cache_type == 0)
-    goto err;
+  /*
+    Testing 'query_cache_size' without a lock here is safe: the thing
+    we may loose is that the query won't be served from cache, but we
+    save on mutex locking in the case when query cache is disabled.
 
-  /* Check that we haven't forgot to reset the query cache variables */
-  DBUG_ASSERT(thd->net.query_cache_query == 0);
+    See also a note on double-check locking usage above.
+  */
+  if (thd->locked_tables || thd->variables.query_cache_type == 0 ||
+      query_cache_size == 0)
+    goto err;
 
   if (!thd->lex->safe_to_cache_query)
   {
@@ -1012,11 +1070,15 @@ Query_cache::send_result_to_client(THD *
   }
 
   STRUCT_LOCK(&structure_guard_mutex);
-  if (query_cache_size == 0)
+  if (query_cache_size == 0 || flush_in_progress)
   {
     DBUG_PRINT("qcache", ("query cache disabled"));
     goto err_unlock;
   }
+
+  /* Check that we haven't forgot to reset the query cache variables */
+  DBUG_ASSERT(thd->net.query_cache_query == 0);
+
   Query_cache_block *query_block;
 
   tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE;
@@ -1242,45 +1304,43 @@ void Query_cache::invalidate(THD *thd, T
 			     my_bool using_transactions)
 {
   DBUG_ENTER("Query_cache::invalidate (table list)");
-  if (query_cache_size > 0)
+  STRUCT_LOCK(&structure_guard_mutex);
+  if (query_cache_size > 0 && !flush_in_progress)
   {
-    STRUCT_LOCK(&structure_guard_mutex);
-    if (query_cache_size > 0)
-    {
-      DUMP(this);
+    DUMP(this);
 
-      using_transactions = using_transactions &&
-	(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
-      for (; tables_used; tables_used= tables_used->next_local)
-      {
-	DBUG_ASSERT(!using_transactions || tables_used->table!=0);
-	if (tables_used->derived)
-	  continue;
-	if (using_transactions &&
-	   (tables_used->table->file->table_cache_type() ==
-	    HA_CACHE_TBL_TRANSACT))
-	  /*
-	     Tables_used->table can't be 0 in transaction.
-	     Only 'drop' invalidate not opened table, but 'drop'
-	     force transaction finish.
-	  */
-	  thd->add_changed_table(tables_used->table);
-	else
-	  invalidate_table(tables_used);
-      }
+    using_transactions= using_transactions &&
+      (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
+    for (; tables_used; tables_used= tables_used->next_local)
+    {
+      DBUG_ASSERT(!using_transactions || tables_used->table!=0);
+      if (tables_used->derived)
+        continue;
+      if (using_transactions &&
+         (tables_used->table->file->table_cache_type() ==
+          HA_CACHE_TBL_TRANSACT))
+        /*
+           Tables_used->table can't be 0 in transaction.
+           Only 'drop' invalidate not opened table, but 'drop'
+           force transaction finish.
+        */
+        thd->add_changed_table(tables_used->table);
+      else
+        invalidate_table(tables_used);
     }
-    STRUCT_UNLOCK(&structure_guard_mutex);
   }
+  STRUCT_UNLOCK(&structure_guard_mutex);
+
   DBUG_VOID_RETURN;
 }
 
 void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
 {
   DBUG_ENTER("Query_cache::invalidate (changed table list)");
-  if (query_cache_size > 0 && tables_used)
+  if (tables_used)
   {
     STRUCT_LOCK(&structure_guard_mutex);
-    if (query_cache_size > 0)
+    if (query_cache_size > 0 && !flush_in_progress)
     {
       DUMP(this);
       for (; tables_used; tables_used= tables_used->next)
@@ -1310,10 +1370,10 @@ void Query_cache::invalidate(CHANGED_TAB
 void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used)
 {
   DBUG_ENTER("Query_cache::invalidate_locked_for_write");
-  if (query_cache_size > 0 && tables_used)
+  if (tables_used)
   {
     STRUCT_LOCK(&structure_guard_mutex);
-    if (query_cache_size > 0)
+    if (query_cache_size > 0 && !flush_in_progress)
     {
       DUMP(this);
       for (; tables_used; tables_used= tables_used->next_local)
@@ -1337,21 +1397,19 @@ void Query_cache::invalidate(THD *thd, T
 {
   DBUG_ENTER("Query_cache::invalidate (table)");
   
-  if (query_cache_size > 0)
+  STRUCT_LOCK(&structure_guard_mutex);
+  if (query_cache_size > 0 && !flush_in_progress)
   {
-    STRUCT_LOCK(&structure_guard_mutex);
-    if (query_cache_size > 0)
-    {
-      using_transactions = using_transactions &&
-	(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
-      if (using_transactions && 
-	  (table->file->table_cache_type() == HA_CACHE_TBL_TRANSACT))
-	thd->add_changed_table(table);
-      else
-	invalidate_table(table);
-    }
-    STRUCT_UNLOCK(&structure_guard_mutex);
+    using_transactions= using_transactions &&
+      (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
+    if (using_transactions && 
+        (table->file->table_cache_type() == HA_CACHE_TBL_TRANSACT))
+      thd->add_changed_table(table);
+    else
+      invalidate_table(table);
   }
+  STRUCT_UNLOCK(&structure_guard_mutex);
+
   DBUG_VOID_RETURN;
 }
 
@@ -1360,20 +1418,18 @@ void Query_cache::invalidate(THD *thd, c
 {
   DBUG_ENTER("Query_cache::invalidate (key)");
   
-  if (query_cache_size > 0)
+  STRUCT_LOCK(&structure_guard_mutex);
+  if (query_cache_size > 0 && !flush_in_progress)
   {
-    using_transactions = using_transactions &&
+    using_transactions= using_transactions &&
       (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
     if (using_transactions) // used for innodb => has_transactions() is TRUE
       thd->add_changed_table(key, key_length);
     else
-    {
-      STRUCT_LOCK(&structure_guard_mutex);
-      if (query_cache_size > 0)
-	invalidate_table((byte*)key, key_length);
-      STRUCT_UNLOCK(&structure_guard_mutex);  
-    }
+      invalidate_table((byte*)key, key_length);
   }
+  STRUCT_UNLOCK(&structure_guard_mutex);  
+
   DBUG_VOID_RETURN;
 }
 
@@ -1384,38 +1440,36 @@ void Query_cache::invalidate(THD *thd, c
 void Query_cache::invalidate(char *db)
 {
   DBUG_ENTER("Query_cache::invalidate (db)");
-  if (query_cache_size > 0)
+  STRUCT_LOCK(&structure_guard_mutex);
+  if (query_cache_size > 0 && !flush_in_progress)
   {
-    STRUCT_LOCK(&structure_guard_mutex);
-    if (query_cache_size > 0)
-    {
-      DUMP(this);
+    DUMP(this);
   restart_search:
-      if (tables_blocks)
+    if (tables_blocks)
+    {
+      Query_cache_block *curr= tables_blocks;
+      Query_cache_block *next;
+      do
       {
-	Query_cache_block *curr= tables_blocks;
-	Query_cache_block *next;
-	do
-	{
-	  next= curr->next;
-	  if (strcmp(db, (char*)(curr->table()->db())) == 0)
-	    invalidate_table(curr);
-	  /*
-	    invalidate_table can freed block on which point 'next' (if
-	    table of this block used only in queries which was deleted
-	    by invalidate_table). As far as we do not allocate new blocks
-	    and mark all headers of freed blocks as 'FREE' (even if they are
-	    merged with other blocks) we can just test type of block
-	    to be sure that block is not deleted
-	  */
-	  if (next->type == Query_cache_block::FREE)
-	    goto restart_search;
-	  curr= next;
-	} while (curr != tables_blocks);
-      }
+        next= curr->next;
+        if (strcmp(db, (char*)(curr->table()->db())) == 0)
+          invalidate_table(curr);
+        /*
+          invalidate_table can freed block on which point 'next' (if
+          table of this block used only in queries which was deleted
+          by invalidate_table). As far as we do not allocate new blocks
+          and mark all headers of freed blocks as 'FREE' (even if they are
+          merged with other blocks) we can just test type of block
+          to be sure that block is not deleted
+        */
+        if (next->type == Query_cache_block::FREE)
+          goto restart_search;
+        curr= next;
+      } while (curr != tables_blocks);
     }
-    STRUCT_UNLOCK(&structure_guard_mutex);
   }
+  STRUCT_UNLOCK(&structure_guard_mutex);
+
   DBUG_VOID_RETURN;
 }
 
@@ -1423,23 +1477,22 @@ void Query_cache::invalidate(char *db)
 void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
 {
   DBUG_ENTER("Query_cache::invalidate_by_MyISAM_filename");
-  if (query_cache_size > 0)
+
+  STRUCT_LOCK(&structure_guard_mutex);
+  if (query_cache_size > 0 && !flush_in_progress)
   {
     /* Calculate the key outside the lock to make the lock shorter */
     char key[MAX_DBKEY_LENGTH];
     uint32 db_length;
     uint key_length= filename_2_table_key(key, filename, &db_length);
-    STRUCT_LOCK(&structure_guard_mutex);
-    if (query_cache_size > 0)			// Safety if cache removed
-    {
-      Query_cache_block *table_block;
-      if ((table_block = (Query_cache_block*) hash_search(&tables,
-							  (byte*) key,
-							  key_length)))
-	invalidate_table(table_block);
-    }
-    STRUCT_UNLOCK(&structure_guard_mutex);
+    Query_cache_block *table_block;
+    if ((table_block = (Query_cache_block*) hash_search(&tables,
+      						  (byte*) key,
+      						  key_length)))
+      invalidate_table(table_block);
   }
+  STRUCT_UNLOCK(&structure_guard_mutex);
+
   DBUG_VOID_RETURN;
 }
 
@@ -1484,7 +1537,12 @@ void Query_cache::destroy()
   }
   else
   {
+    /* Underlying code expects the lock. */
+    STRUCT_LOCK(&structure_guard_mutex);
     free_cache();
+    STRUCT_UNLOCK(&structure_guard_mutex);
+
+    pthread_cond_destroy(&COND_flush_finished);
     pthread_mutex_destroy(&structure_guard_mutex);
     initialized = 0;
   }
@@ -1500,6 +1558,8 @@ void Query_cache::init()
 {
   DBUG_ENTER("Query_cache::init");
   pthread_mutex_init(&structure_guard_mutex,MY_MUTEX_INIT_FAST);
+  pthread_cond_init(&COND_flush_finished, NULL);
+  flush_in_progress= FALSE;
   initialized = 1;
   DBUG_VOID_RETURN;
 }
@@ -1695,6 +1755,17 @@ void Query_cache::make_disabled()
 }
 
 
+/*
+  free_cache() - free all resources allocated by the cache.
+
+  SYNOPSIS
+    free_cache()
+
+  DESCRIPTION
+    This function frees all resources allocated by the cache.  You
+    have to call init_cache() before using the cache again.
+*/
+
 void Query_cache::free_cache()
 {
   DBUG_ENTER("Query_cache::free_cache");
@@ -1729,17 +1800,51 @@ void Query_cache::free_cache()
   Free block data
 *****************************************************************************/
 
+
 /*
-  The following assumes we have a lock on the cache
+  flush_cache() - flush the cache.
+
+  SYNOPSIS
+    flush_cache()
+
+  DESCRIPTION
+    This function will flush cache contents.  It assumes we have
+    'structure_guard_mutex' locked.  The function sets the
+    flush_in_progress flag and releases the lock, so other threads may
+    proceed skipping the cache as if it is disabled.  Concurrent
+    flushes are performed in turn.
 */
 
 void Query_cache::flush_cache()
 {
+  /*
+    If there is flush in progress, wait for it to finish, and then do
+    our flush.  This is necessary because something could be added to
+    the cache before we acquire the lock again, and some code (like
+    Query_cache::free_cache()) depends on the fact that after the
+    flush the cache is empty.
+  */
+  while (flush_in_progress)
+    pthread_cond_wait(&COND_flush_finished, &structure_guard_mutex);
+
+  /*
+    Setting 'flush_in_progress' will prevent other threads from using
+    the cache while we are in the middle of the flush, and we release
+    the lock so that other threads won't block.
+  */
+  flush_in_progress= TRUE;
+  STRUCT_UNLOCK(&structure_guard_mutex);
+
+  my_hash_reset(&queries);
   while (queries_blocks != 0)
   {
     BLOCK_LOCK_WR(queries_blocks);
-    free_query(queries_blocks);
+    free_query_internal(queries_blocks);
   }
+
+  STRUCT_LOCK(&structure_guard_mutex);
+  flush_in_progress= FALSE;
+  pthread_cond_signal(&COND_flush_finished);
 }
 
 /*
@@ -1785,36 +1890,48 @@ my_bool Query_cache::free_old_query()
   DBUG_RETURN(1);				// Nothing to remove
 }
 
+
 /*
-  Free query from query cache.
-  query_block must be locked for writing.
-  This function will remove (and destroy) the lock for the query.
+  free_query_internal() - free query from query cache.
+
+  SYNOPSIS
+    free_query_internal()
+      query_block           Query_cache_block representing the query
+
+  DESCRIPTION
+    This function will remove the query from a cache, and place its
+    memory blocks to the list of free blocks.  'query_block' must be
+    locked for writing, this function will release (and destroy) this
+    lock.
+
+  NOTE
+    'query_block' should be removed from 'queries' hash _before_
+    calling this method, as the lock will be destroyed here.
 */
 
-void Query_cache::free_query(Query_cache_block *query_block)
+void Query_cache::free_query_internal(Query_cache_block *query_block)
 {
-  DBUG_ENTER("Query_cache::free_query");
+  DBUG_ENTER("Query_cache::free_query_internal");
   DBUG_PRINT("qcache", ("free query 0x%lx %lu bytes result",
 		      (ulong) query_block,
 		      query_block->query()->length() ));
 
   queries_in_cache--;
-  hash_delete(&queries,(byte *) query_block);
 
-  Query_cache_query *query = query_block->query();
+  Query_cache_query *query= query_block->query();
 
   if (query->writer() != 0)
   {
     /* Tell MySQL that this query should not be cached anymore */
-    query->writer()->query_cache_query = 0;
+    query->writer()->query_cache_query= 0;
     query->writer(0);
   }
   double_linked_list_exclude(query_block, &queries_blocks);
-  Query_cache_block_table *table=query_block->table(0);
+  Query_cache_block_table *table= query_block->table(0);
 
-  for (TABLE_COUNTER_TYPE i=0; i < query_block->n_tables; i++)
+  for (TABLE_COUNTER_TYPE i= 0; i < query_block->n_tables; i++)
     unlink_table(table++);
-  Query_cache_block *result_block = query->result();
+  Query_cache_block *result_block= query->result();
 
   /*
     The following is true when query destruction was called and no results
@@ -1828,11 +1945,11 @@ void Query_cache::free_query(Query_cache
       refused++;
       inserts--;
     }
-    Query_cache_block *block = result_block;
+    Query_cache_block *block= result_block;
     do
     {
-      Query_cache_block *current = block;
-      block = block->next;
+      Query_cache_block *current= block;
+      block= block->next;
       free_memory_block(current);
     } while (block != result_block);
   }
@@ -1849,6 +1966,32 @@ void Query_cache::free_query(Query_cache
   DBUG_VOID_RETURN;
 }
 
+
+/*
+  free_query() - free query from query cache.
+
+  SYNOPSIS
+    free_query()
+      query_block           Query_cache_block representing the query
+
+  DESCRIPTION
+    This function will remove 'query_block' from 'queries' hash, and
+    then call free_query_internal(), which see.
+*/
+
+void Query_cache::free_query(Query_cache_block *query_block)
+{
+  DBUG_ENTER("Query_cache::free_query");
+  DBUG_PRINT("qcache", ("free query 0x%lx %lu bytes result",
+		      (ulong) query_block,
+		      query_block->query()->length() ));
+
+  hash_delete(&queries,(byte *) query_block);
+  free_query_internal(query_block);
+
+  DBUG_VOID_RETURN;
+}
+
 /*****************************************************************************
  Query data creation
 *****************************************************************************/
@@ -2434,12 +2577,8 @@ Query_cache::allocate_block(ulong len, m
   if (!under_guard)
   {
     STRUCT_LOCK(&structure_guard_mutex);
-    /*
-      It is very unlikely that following condition is TRUE (it is possible
-      only if other thread is resizing cache), so we check it only after
-      guard mutex lock
-    */
-    if (unlikely(query_cache.query_cache_size == 0))
+
+    if (unlikely(query_cache.query_cache_size == 0 || flush_in_progress))
     {
       STRUCT_UNLOCK(&structure_guard_mutex);
       DBUG_RETURN(0);
@@ -2895,11 +3034,9 @@ static TABLE_COUNTER_TYPE process_and_co
   (query without tables are not cached)
 */
 
-TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
-					     char *query,
-					     LEX *lex,
-					     TABLE_LIST *tables_used,
-					     uint8 *tables_type)
+TABLE_COUNTER_TYPE
+Query_cache::is_cacheable(THD *thd, uint32 query_len, char *query, LEX *lex,
+                          TABLE_LIST *tables_used, uint8 *tables_type)
 {
   TABLE_COUNTER_TYPE table_count;
   DBUG_ENTER("Query_cache::is_cacheable");
@@ -2984,13 +3121,10 @@ my_bool Query_cache::ask_handler_allowan
 void Query_cache::pack_cache()
 {
   DBUG_ENTER("Query_cache::pack_cache");
+
   STRUCT_LOCK(&structure_guard_mutex);
-  /*
-    It is very unlikely that following condition is TRUE (it is possible
-    only if other thread is resizing cache), so we check it only after
-    guard mutex lock
-  */
-  if (unlikely(query_cache_size == 0))
+
+  if (unlikely(query_cache_size == 0 || flush_in_progress))
   {
     STRUCT_UNLOCK(&structure_guard_mutex);
     DBUG_VOID_RETURN;
@@ -3305,7 +3439,7 @@ my_bool Query_cache::join_results(ulong 
   DBUG_ENTER("Query_cache::join_results");
 
   STRUCT_LOCK(&structure_guard_mutex);
-  if (queries_blocks != 0)
+  if (queries_blocks != 0 && !flush_in_progress)
   {
     DBUG_ASSERT(query_cache_size > 0);
     Query_cache_block *block = queries_blocks;
@@ -3592,31 +3726,23 @@ void Query_cache::tables_dump()
 }
 
 
-my_bool Query_cache::check_integrity(bool not_locked)
+my_bool Query_cache::check_integrity(bool locked)
 {
   my_bool result = 0;
   uint i;
   DBUG_ENTER("check_integrity");
 
-  if (query_cache_size == 0)
+  if (!locked)
+    STRUCT_LOCK(&structure_guard_mutex);
+
+  if (unlikely(query_cache_size == 0 || flush_in_progress))
   {
+    if (!locked)
+      STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+
     DBUG_PRINT("qcache", ("Query Cache not initialized"));
     DBUG_RETURN(0);
   }
-  if (!not_locked)
-  {
-    STRUCT_LOCK(&structure_guard_mutex);
-    /*
-      It is very unlikely that following condition is TRUE (it is possible
-      only if other thread is resizing cache), so we check it only after
-      guard mutex lock
-    */
-    if (unlikely(query_cache_size == 0))
-    {
-      STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
-      DBUG_RETURN(0);
-    }
-  }
 
   if (hash_check(&queries))
   {
@@ -3861,7 +3987,7 @@ my_bool Query_cache::check_integrity(boo
     }
   }
   DBUG_ASSERT(result == 0);
-  if (!not_locked)
+  if (!locked)
     STRUCT_UNLOCK(&structure_guard_mutex);
   DBUG_RETURN(result);
 }

--- 1.285/sql/sql_class.cc	2006-08-30 15:25:38 +04:00
+++ 1.286/sql/sql_class.cc	2006-08-30 15:25:38 +04:00
@@ -261,7 +261,7 @@ THD::THD()
 #endif
   client_capabilities= 0;                       // minimalistic client
   net.last_error[0]=0;                          // If error on boot
-  net.query_cache_query=0;                      // If error on boot
+  query_cache_init_query(&net);                 // If error on boot
   ull=0;
   system_thread= NON_SYSTEM_THREAD;
   cleanup_done= abort_on_warning= no_warnings_for_error= 0;
@@ -1983,7 +1983,7 @@ bool select_dumpvar::send_data(List<Item
     {
       if ((xx=li++))
       {
-        xx->check();
+        xx->check(0);
 	xx->update();
       }
     }

--- 1.191/sql/sql_delete.cc	2006-08-30 15:25:38 +04:00
+++ 1.192/sql/sql_delete.cc	2006-08-30 15:25:38 +04:00
@@ -386,7 +386,7 @@ bool mysql_prepare_delete(THD *thd, TABL
                                     &thd->lex->select_lex.top_join_list,
                                     table_list, 
                                     &select_lex->leaf_tables, FALSE, 
-                                    DELETE_ACL) ||
+                                    DELETE_ACL, SELECT_ACL) ||
       setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
       setup_ftfuncs(select_lex))
     DBUG_RETURN(TRUE);
@@ -449,7 +449,7 @@ bool mysql_multi_delete_prepare(THD *thd
                                     &thd->lex->select_lex.top_join_list,
                                     lex->query_tables,
                                     &lex->select_lex.leaf_tables, FALSE, 
-                                    DELETE_ACL))
+                                    DELETE_ACL, SELECT_ACL))
     DBUG_RETURN(TRUE);
 
 

--- 1.220/sql/sql_insert.cc	2006-08-30 15:25:38 +04:00
+++ 1.221/sql/sql_insert.cc	2006-08-30 15:25:38 +04:00
@@ -821,7 +821,7 @@ static bool mysql_prepare_insert_check_t
                                     &thd->lex->select_lex.top_join_list,
                                     table_list,
                                     &thd->lex->select_lex.leaf_tables,
-                                    select_insert, SELECT_ACL))
+                                    select_insert, INSERT_ACL, SELECT_ACL))
     DBUG_RETURN(TRUE);
 
   if (insert_into_view && !fields.elements)

--- 1.103/sql/sql_load.cc	2006-08-30 15:25:38 +04:00
+++ 1.104/sql/sql_load.cc	2006-08-30 15:25:38 +04:00
@@ -156,6 +156,7 @@ bool mysql_load(THD *thd,sql_exchange *e
                                     &thd->lex->select_lex.top_join_list,
                                     table_list,
                                     &thd->lex->select_lex.leaf_tables, FALSE,
+                                    INSERT_ACL | UPDATE_ACL,
                                     INSERT_ACL | UPDATE_ACL))
      DBUG_RETURN(-1);
   if (!table_list->table ||               // do not suport join view

--- 1.580/sql/sql_parse.cc	2006-08-30 15:25:38 +04:00
+++ 1.581/sql/sql_parse.cc	2006-08-30 15:25:38 +04:00
@@ -5354,10 +5354,21 @@ bool check_one_table_access(THD *thd, ul
     return 1;
 
   /* Check rights on tables of subselects and implictly opened tables */
-  TABLE_LIST *subselects_tables;
+  TABLE_LIST *subselects_tables, *view= all_tables->view ? all_tables : 0;
   if ((subselects_tables= all_tables->next_global))
   {
-    if ((check_table_access(thd, SELECT_ACL, subselects_tables, 0)))
+    /*
+      Access rights asked for the first table of a view should be the same
+      as for the view
+    */
+    if (view && subselects_tables->belong_to_view == view)
+    {
+      if (check_single_table_access (thd, privilege, subselects_tables))
+        return 1;
+      subselects_tables= subselects_tables->next_global;
+    }
+    if (subselects_tables &&
+        (check_table_access(thd, SELECT_ACL, subselects_tables, 0)))
       return 1;
   }
   return 0;
@@ -6036,6 +6047,9 @@ void mysql_init_multi_delete(LEX *lex)
 void mysql_parse(THD *thd, char *inBuf, uint length)
 {
   DBUG_ENTER("mysql_parse");
+
+  DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
+
   mysql_init_query(thd, (uchar*) inBuf, length);
   if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
   {
@@ -6943,11 +6957,7 @@ bool reload_acl_and_cache(THD *thd, ulon
   select_errors=0;				/* Write if more errors */
   bool tmp_write_to_binlog= 1;
 
-  if (thd && thd->in_sub_stmt)
-  {
-    my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH");
-    return 1;
-  }
+  DBUG_ASSERT(!thd || !thd->in_sub_stmt);
 
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
   if (options & REFRESH_GRANT)
@@ -7817,16 +7827,34 @@ LEX_USER *create_definer(THD *thd, LEX_S
 
 LEX_USER *get_current_user(THD *thd, LEX_USER *user)
 {
-  LEX_USER *curr_user;
   if (!user->user.str)  // current_user
-  {
-    if (!(curr_user= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
-    {
-      my_error(ER_OUTOFMEMORY, MYF(0), sizeof(LEX_USER));
-      return 0;
-    }
-    get_default_definer(thd, curr_user);
-    return curr_user;
-  }
+    return create_default_definer(thd);
+
   return user;
+}
+
+
+/*
+  Check that length of a string does not exceed some limit.
+
+  SYNOPSIS
+    check_string_length()
+      str         string to be checked
+      err_msg     error message to be displayed if the string is too long
+      max_length  max length
+
+  RETURN
+    FALSE   the passed string is not longer than max_length
+    TRUE    the passed string is longer than max_length
+*/
+
+bool check_string_length(LEX_STRING *str, const char *err_msg,
+                         uint max_length)
+{
+  if (str->length <= max_length)
+    return FALSE;
+
+  my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_length);
+
+  return TRUE;
 }

--- 1.431/sql/sql_select.cc	2006-08-30 15:25:38 +04:00
+++ 1.432/sql/sql_select.cc	2006-08-30 15:25:38 +04:00
@@ -344,7 +344,7 @@ JOIN::prepare(Item ***rref_pointer_array
        setup_tables_and_check_access(thd, &select_lex->context, join_list,
                                      tables_list,
                                      &select_lex->leaf_tables, FALSE, 
-                                     SELECT_ACL)) ||
+                                     SELECT_ACL, SELECT_ACL)) ||
       setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
       select_lex->setup_ref_array(thd, og_num) ||
       setup_fields(thd, (*rref_pointer_array), fields_list, MARK_COLUMNS_READ,
@@ -822,6 +822,40 @@ JOIN::optimize()
     if (!order && org_order)
       skip_sort_order= 1;
   }
+  /*
+     Check if we can optimize away GROUP BY/DISTINCT.
+     We can do that if there are no aggregate functions and the
+     fields in DISTINCT clause (if present) and/or columns in GROUP BY
+     (if present) contain direct references to all key parts of
+     an unique index (in whatever order).
+     Note that the unique keys for DISTINCT and GROUP BY should not
+     be the same (as long as they are unique).
+
+     The FROM clause must contain a single non-constant table.
+  */
+  if (tables - const_tables == 1 && (group_list || select_distinct) &&
+      !tmp_table_param.sum_func_count &&
+      (!join_tab[const_tables].select ||
+       !join_tab[const_tables].select->quick ||
+       join_tab[const_tables].select->quick->get_type() != 
+       QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX))
+  {
+    if (group_list &&
+       list_contains_unique_index(join_tab[const_tables].table,
+                                 find_field_in_order_list,
+                                 (void *) group_list))
+    {
+      group_list= 0;
+      group= 0;
+    }
+    if (select_distinct &&
+       list_contains_unique_index(join_tab[const_tables].table,
+                                 find_field_in_item_list,
+                                 (void *) &fields_list))
+    {
+      select_distinct= 0;
+    }
+  }
   if (group_list || tmp_table_param.sum_func_count)
   {
     if (! hidden_group_fields && rollup.state == ROLLUP::STATE_NONE)
@@ -891,40 +925,6 @@ JOIN::optimize()
     if (old_group_list && !group_list)
       select_distinct= 0;
   }
-  /*
-     Check if we can optimize away GROUP BY/DISTINCT.
-     We can do that if there are no aggregate functions and the
-     fields in DISTINCT clause (if present) and/or columns in GROUP BY
-     (if present) contain direct references to all key parts of
-     an unique index (in whatever order).
-     Note that the unique keys for DISTINCT and GROUP BY should not
-     be the same (as long as they are unique).
-
-     The FROM clause must contain a single non-constant table.
-  */
-  if (tables - const_tables == 1 && (group_list || select_distinct) &&
-      !tmp_table_param.sum_func_count &&
-      (!join_tab[const_tables].select ||
-       !join_tab[const_tables].select->quick ||
-       join_tab[const_tables].select->quick->get_type() != 
-       QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX))
-  {
-    if (group_list &&
-       list_contains_unique_index(join_tab[const_tables].table,
-                                 find_field_in_order_list,
-                                 (void *) group_list))
-    {
-      group_list= 0;
-      group= 0;
-    }
-    if (select_distinct &&
-       list_contains_unique_index(join_tab[const_tables].table,
-                                 find_field_in_item_list,
-                                 (void *) &fields_list))
-    {
-      select_distinct= 0;
-    }
-  }
   if (!group_list && group)
   {
     order=0;					// The output has only one row
@@ -2233,6 +2233,7 @@ make_join_statistics(JOIN *join, TABLE_L
   int ref_changed;
   do
   {
+  more_const_tables_found:
     ref_changed = 0;
     found_ref=0;
 
@@ -2244,6 +2245,30 @@ make_join_statistics(JOIN *join, TABLE_L
     for (JOIN_TAB **pos=stat_vector+const_count ; (s= *pos) ; pos++)
     {
       table=s->table;
+
+      /* 
+        If equi-join condition by a key is null rejecting and after a
+        substitution of a const table the key value happens to be null
+        then we can state that there are no matches for this equi-join.
+      */  
+      if ((keyuse= s->keyuse) && *s->on_expr_ref)
+      {
+        while (keyuse->table == table)
+        {
+          if (!(keyuse->val->used_tables() & ~join->const_table_map) &&
+              keyuse->val->is_null() && keyuse->null_rejecting)
+          {
+            s->type= JT_CONST;
+            mark_as_null_row(table);
+            found_const_table_map|= table->map;
+	    join->const_table_map|= table->map;
+	    set_position(join,const_count++,s,(KEYUSE*) 0);
+            goto more_const_tables_found;
+           }
+	  keyuse++;
+        }
+      }
+
       if (s->dependent)				// If dependent on some table
       {
 	// All dep. must be constants
@@ -2294,34 +2319,38 @@ make_join_statistics(JOIN *join, TABLE_L
 	  } while (keyuse->table == table && keyuse->key == key);
 
 	  if (eq_part.is_prefix(table->key_info[key].key_parts) &&
-	      ((table->key_info[key].flags & (HA_NOSAME | HA_END_SPACE_KEY)) ==
-	       HA_NOSAME) &&
               !table->fulltext_searched && 
               !table->pos_in_table_list->embedding)
 	  {
-	    if (const_ref == eq_part)
-	    {					// Found everything for ref.
-	      int tmp;
-	      ref_changed = 1;
-	      s->type= JT_CONST;
-	      join->const_table_map|=table->map;
-	      set_position(join,const_count++,s,start_keyuse);
-	      if (create_ref_for_key(join, s, start_keyuse,
-				     found_const_table_map))
-		DBUG_RETURN(1);
-	      if ((tmp=join_read_const_table(s,
-                                             join->positions+const_count-1)))
-	      {
-		if (tmp > 0)
-		  DBUG_RETURN(1);			// Fatal error
+            if ((table->key_info[key].flags & (HA_NOSAME | HA_END_SPACE_KEY))
+                 == HA_NOSAME)
+            {
+	      if (const_ref == eq_part)
+	      {					// Found everything for ref.
+	        int tmp;
+	        ref_changed = 1;
+	        s->type= JT_CONST;
+	        join->const_table_map|=table->map;
+	        set_position(join,const_count++,s,start_keyuse);
+	        if (create_ref_for_key(join, s, start_keyuse,
+				       found_const_table_map))
+		  DBUG_RETURN(1);
+	        if ((tmp=join_read_const_table(s,
+                                               join->positions+const_count-1)))
+	        {
+		  if (tmp > 0)
+		    DBUG_RETURN(1);			// Fatal error
+	        }
+	        else
+		  found_const_table_map|= table->map;
+	        break;
 	      }
 	      else
-		found_const_table_map|= table->map;
-	      break;
+	        found_ref|= refs;      // Table is const if all refs are const
 	    }
-	    else
-	      found_ref|= refs;		// Table is const if all refs are const
-	  }
+            else if (const_ref == eq_part)
+              s->const_keys.set_bit(key);
+          }
 	}
       }
     }
@@ -2727,7 +2756,8 @@ add_key_field(KEY_FIELD **key_fields,uin
     We use null_rejecting in add_not_null_conds() to add
     'othertbl.field IS NOT NULL' to tab->select_cond.
   */
-  (*key_fields)->null_rejecting= ((cond->functype() == Item_func::EQ_FUNC) &&
+  (*key_fields)->null_rejecting= ((cond->functype() == Item_func::EQ_FUNC ||
+                                   cond->functype() == Item_func::MULT_EQUAL_FUNC) &&
                                   ((*value)->type() == Item::FIELD_ITEM) &&
                                   ((Item_field*)*value)->field->maybe_null());
   (*key_fields)++;
@@ -2827,11 +2857,12 @@ add_key_fields(KEY_FIELD **key_fields,ui
     break;
   case Item_func::OPTIMIZE_KEY:
   {
+    Item **values;
     // BETWEEN, IN, NE
     if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM &&
 	!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
     {
-      Item **values= cond_func->arguments()+1;
+      values= cond_func->arguments()+1;
       if (cond_func->functype() == Item_func::NE_FUNC &&
         cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
 	     !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT))
@@ -2844,6 +2875,22 @@ add_key_fields(KEY_FIELD **key_fields,ui
                            cond_func->argument_count()-1,
                            usable_tables);
     }
+    if (cond_func->functype() == Item_func::BETWEEN)
+    {
+      values= cond_func->arguments();
+      for (uint i= 1 ; i < cond_func->argument_count() ; i++)
+      {
+        Item_field *field_item;
+        if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM
+            &&
+            !(cond_func->arguments()[i]->used_tables() & OUTER_REF_TABLE_BIT))
+        {
+          field_item= (Item_field *) (cond_func->arguments()[i]->real_item());
+          add_key_equal_fields(key_fields, *and_level, cond_func,
+                               field_item, 0, values, 1, usable_tables);
+        }
+      }  
+    }
     break;
   }
   case Item_func::OPTIMIZE_OP:
@@ -3476,7 +3523,7 @@ best_access_path(JOIN      *join,
                                                  keyuse->used_tables));
             if (tmp < best_prev_record_reads)
             {
-              best_part_found_ref= keyuse->used_tables;
+              best_part_found_ref= keyuse->used_tables & ~join->const_table_map;
               best_prev_record_reads= tmp;
             }
             if (rec > keyuse->ref_table_rows)
@@ -6034,7 +6081,8 @@ eq_ref_table(JOIN *join, ORDER *start_or
   if (tab->cached_eq_ref_table)			// If cached
     return tab->eq_ref_table;
   tab->cached_eq_ref_table=1;
-  if (tab->type == JT_CONST)			// We can skip const tables
+  /* We can skip const tables only if not an outer table */
+  if (tab->type == JT_CONST && !tab->first_inner)
     return (tab->eq_ref_table=1);		/* purecov: inspected */
   if (tab->type != JT_EQ_REF || tab->table->maybe_null)
     return (tab->eq_ref_table=0);		// We must use this
@@ -6556,6 +6604,7 @@ static bool check_equality(Item *item, C
         field_item= (Item_field*) right_item;
         const_item= left_item;
       }
+
       if (const_item &&
           field_item->result_type() == const_item->result_type())
       {
@@ -7213,6 +7262,7 @@ change_cond_ref_to_const(THD *thd, I_Lis
   Item_func::Functype functype=  func->functype();
 
   if (right_item->eq(field,0) && left_item != value &&
+      right_item->cmp_context == field->cmp_context &&
       (left_item->result_type() != STRING_RESULT ||
        value->result_type() != STRING_RESULT ||
        left_item->collation.collation == value->collation.collation))
@@ -7234,6 +7284,7 @@ change_cond_ref_to_const(THD *thd, I_Lis
     }
   }
   else if (left_item->eq(field,0) && right_item != value &&
+           left_item->cmp_context == field->cmp_context &&
            (right_item->result_type() != STRING_RESULT ||
             value->result_type() != STRING_RESULT ||
             right_item->collation.collation == value->collation.collation))
@@ -11619,6 +11670,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,OR
     We must not try to use disabled keys.
   */
   usable_keys= table->s->keys_in_use;
+  /* we must not consider keys that are disabled by IGNORE INDEX */
+  usable_keys.intersect(table->keys_in_use_for_query);
 
   for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
   {
@@ -13489,7 +13542,9 @@ change_to_use_tmp_fields(THD *thd, Item 
   {
     Field *field;
 
-    if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
+    if ((item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) ||
+        (item->type() == Item::FUNC_ITEM &&
+         ((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC))
       item_field= item;
     else
     {

--- 1.204/sql/sql_update.cc	2006-08-30 15:25:38 +04:00
+++ 1.205/sql/sql_update.cc	2006-08-30 15:25:38 +04:00
@@ -746,7 +746,7 @@ bool mysql_prepare_update(THD *thd, TABL
                                     &select_lex->top_join_list,
                                     table_list,
                                     &select_lex->leaf_tables,
-                                    FALSE, UPDATE_ACL) ||
+                                    FALSE, UPDATE_ACL, SELECT_ACL) ||
       setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
       select_lex->setup_ref_array(thd, order_num) ||
       setup_order(thd, select_lex->ref_pointer_array,
@@ -841,7 +841,7 @@ reopen_tables:
                                     &lex->select_lex.top_join_list,
                                     table_list,
                                     &lex->select_lex.leaf_tables, FALSE,
-                                    UPDATE_ACL))
+                                    UPDATE_ACL, SELECT_ACL))
     DBUG_RETURN(TRUE);
 
   if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0))

--- 1.494/sql/sql_yacc.yy	2006-08-30 15:25:38 +04:00
+++ 1.495/sql/sql_yacc.yy	2006-08-30 15:25:38 +04:00
@@ -64,6 +64,34 @@ inline Item *is_truth_value(Item *A, boo
 	new Item_int((char *) (v1 ? "FALSE" : "TRUE"),!v1, 1));
 }
 
+#ifndef DBUG_OFF
+#define YYDEBUG 1
+#else
+#define YYDEBUG 0
+#endif
+
+#ifndef DBUG_OFF
+void turn_parser_debug_on()
+{
+  /*
+     MYSQLdebug is in sql/sql_yacc.cc, in bison generated code.
+     Turning this option on is **VERY** verbose, and should be
+     used when investigating a syntax error problem only.
+
+     The syntax to run with bison traces is as follows :
+     - Starting a server manually :
+       mysqld --debug="d,parser_debug" ...
+     - Running a test :
+       mysql-test-run.pl --mysqld="--debug=d,parser_debug" ...
+
+     The result will be in the process stderr (var/log/master.err)
+   */
+
+  extern int yydebug;
+  yydebug= 1;
+}
+#endif
+
 %}
 %union {
   int  num;
@@ -8565,17 +8593,8 @@ flush:
 	FLUSH_SYM opt_no_write_to_binlog
 	{
 	  LEX *lex=Lex;
-	  if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE)
-	  {
-            /*
-              Note that both FLUSH TABLES and FLUSH PRIVILEGES will break
-              execution in prelocked mode. So it is better to disable
-              FLUSH in stored functions and triggers completely.
-            */
-            my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH");
-	    YYABORT;
-	  }
-	  lex->sql_command= SQLCOM_FLUSH; lex->type=0;
+	  lex->sql_command= SQLCOM_FLUSH;
+          lex->type= 0;
           lex->no_write_to_binlog= $2;
 	}
 	flush_options
@@ -9301,6 +9320,9 @@ user:
 	  $$->user = $1;
 	  $$->host.str= (char *) "%";
 	  $$->host.length= 1;
+
+	  if (check_string_length(&$$->user, ER(ER_USERNAME), USERNAME_LENGTH))
+	    YYABORT;
 	}
 	| ident_or_text '@' ident_or_text
 	  {
@@ -9308,6 +9330,11 @@ user:
 	    if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
 	      YYABORT;
 	    $$->user = $1; $$->host=$3;
+
+	    if (check_string_length(&$$->user, ER(ER_USERNAME), USERNAME_LENGTH) ||
+	        check_string_length(&$$->host, ER(ER_HOSTNAME),
+					       HOSTNAME_LENGTH))
+	      YYABORT;
 	  }
 	| CURRENT_USER optional_braces
 	{
@@ -10826,15 +10853,9 @@ definer:
            */
           YYTHD->lex->definer= 0;
 	}
-	| DEFINER_SYM EQ CURRENT_USER optional_braces
-	{
-          if (! (YYTHD->lex->definer= create_default_definer(YYTHD)))
-            YYABORT;
-	}
-	| DEFINER_SYM EQ ident_or_text '@' ident_or_text
+	| DEFINER_SYM EQ user
 	{
-          if (!(YYTHD->lex->definer= create_definer(YYTHD, &$3, &$5)))
-            YYABORT;
+	  YYTHD->lex->definer= get_current_user(YYTHD, $3);
 	}
 	;
 

--- 1.5/mysql-test/r/im_daemon_life_cycle.result	2006-08-30 15:25:38 +04:00
+++ 1.6/mysql-test/r/im_daemon_life_cycle.result	2006-08-30 15:25:38 +04:00
@@ -1,4 +1,3 @@
-Success: the process has been started.
 SHOW VARIABLES LIKE 'server_id';
 Variable_name	Value
 server_id	1

--- 1.13/mysql-test/r/im_life_cycle.result	2006-08-30 15:25:38 +04:00
+++ 1.14/mysql-test/r/im_life_cycle.result	2006-08-30 15:25:38 +04:00
@@ -1,4 +1,3 @@
-Success: the process has been started.
 SHOW VARIABLES LIKE 'server_id';
 Variable_name	Value
 server_id	1

--- 1.9/mysql-test/r/im_utils.result	2006-08-30 15:25:38 +04:00
+++ 1.10/mysql-test/r/im_utils.result	2006-08-30 15:25:38 +04:00
@@ -1,4 +1,3 @@
-Success: the process has been started.
 SHOW VARIABLES LIKE 'server_id';
 Variable_name	Value
 server_id	1

--- 1.4/mysql-test/t/im_daemon_life_cycle.imtest	2006-08-30 15:25:38 +04:00
+++ 1.5/mysql-test/t/im_daemon_life_cycle.imtest	2006-08-30 15:25:38 +04:00
@@ -6,7 +6,6 @@
 #
 ###########################################################################
 
---source include/im_check_os.inc
 --source include/im_check_env.inc
 
 ###########################################################################

--- 1.9/mysql-test/t/im_life_cycle.imtest	2006-08-30 15:25:38 +04:00
+++ 1.10/mysql-test/t/im_life_cycle.imtest	2006-08-30 15:25:38 +04:00
@@ -6,7 +6,6 @@
 #
 ###########################################################################
 
---source include/im_check_os.inc
 --source include/im_check_env.inc
 
 ###########################################################################

--- 1.4/mysql-test/t/im_utils.imtest	2006-08-30 15:25:38 +04:00
+++ 1.5/mysql-test/t/im_utils.imtest	2006-08-30 15:25:38 +04:00
@@ -6,7 +6,6 @@
 #
 ###########################################################################
 
---source include/im_check_os.inc
 --source include/im_check_env.inc
 
 ###########################################################################

--- 1.150/mysql-test/r/subselect.result	2006-08-30 15:25:38 +04:00
+++ 1.151/mysql-test/r/subselect.result	2006-08-30 15:25:38 +04:00
@@ -2915,6 +2915,28 @@ select * from t1 where NOT(s1 = ALL (sel
 s1
 2
 drop table t1;
+create table t1 (
+retailerID varchar(8) NOT NULL,
+statusID   int(10) unsigned NOT NULL,
+changed    datetime NOT NULL,
+UNIQUE KEY retailerID (retailerID, statusID, changed)
+);
+INSERT INTO t1 VALUES("0026", "1", "2005-12-06 12:18:56");
+INSERT INTO t1 VALUES("0026", "2", "2006-01-06 12:25:53");
+INSERT INTO t1 VALUES("0037", "1", "2005-12-06 12:18:56");
+INSERT INTO t1 VALUES("0037", "2", "2006-01-06 12:25:53");
+INSERT INTO t1 VALUES("0048", "1", "2006-01-06 12:37:50");
+INSERT INTO t1 VALUES("0059", "1", "2006-01-06 12:37:50");
+select * from t1 r1 
+where (r1.retailerID,(r1.changed)) in 
+(SELECT r2.retailerId,(max(changed)) from t1 r2 
+group by r2.retailerId);
+retailerID	statusID	changed
+0026	2	2006-01-06 12:25:53
+0037	2	2006-01-06 12:25:53
+0048	1	2006-01-06 12:37:50
+0059	1	2006-01-06 12:37:50
+drop table t1;
 create table t1 (df decimal(5,1));
 insert into t1 values(1.1);
 insert into t1 values(2.2);

--- 1.172/mysql-test/r/view.result	2006-08-30 15:25:38 +04:00
+++ 1.173/mysql-test/r/view.result	2006-08-30 15:25:38 +04:00
@@ -2850,3 +2850,70 @@ Tables_in_test
 t1
 DROP TABLE t1;
 DROP VIEW IF EXISTS v1;
+CREATE DATABASE bug21261DB;
+USE bug21261DB;
+CREATE TABLE t1 (x INT);
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT x FROM t1;
+GRANT INSERT, UPDATE ON v1 TO 'user21261'@'localhost';
+GRANT INSERT, UPDATE ON t1 TO 'user21261'@'localhost';
+CREATE TABLE t2 (y INT);
+GRANT SELECT ON t2 TO 'user21261'@'localhost';
+INSERT INTO v1 (x) VALUES (5);
+UPDATE v1 SET x=1;
+GRANT SELECT ON v1 TO 'user21261'@'localhost';
+GRANT SELECT ON t1 TO 'user21261'@'localhost';
+UPDATE v1,t2 SET x=1 WHERE x=y;
+SELECT * FROM t1;
+x
+1
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'user21261'@'localhost';
+DROP USER 'user21261'@'localhost';
+DROP VIEW v1;
+DROP TABLE t1;
+DROP DATABASE bug21261DB;
+USE test;
+create table t1 (f1 datetime);
+create view v1 as select * from t1 where f1 between now() and now() + interval 1 minute;
+show create view v1;
+View	Create View
+v1	CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` where (`t1`.`f1` between now() and (now() + interval 1 minute))
+drop view v1;
+drop table t1;
+DROP TABLE IF EXISTS t1;
+DROP VIEW IF EXISTS v1;
+DROP VIEW IF EXISTS v2;
+CREATE TABLE t1(a INT, b INT);
+CREATE DEFINER=1234567890abcdefGHIKL@localhost
+VIEW v1 AS SELECT a FROM t1;
+ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
+CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
+VIEW v2 AS SELECT b FROM t1;
+ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
+DROP TABLE t1;
+DROP FUNCTION IF EXISTS f1;
+DROP FUNCTION IF EXISTS f2;
+DROP VIEW IF EXISTS v1, v2;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (i INT);
+CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE FUNCTION f1() RETURNS INT
+BEGIN
+INSERT INTO v1 VALUES (0);
+RETURN 0;
+END |
+SELECT f1();
+f1()
+0
+CREATE ALGORITHM=TEMPTABLE VIEW v2 AS SELECT * FROM t1;
+CREATE FUNCTION f2() RETURNS INT
+BEGIN
+INSERT INTO v2 VALUES (0);
+RETURN 0;
+END |
+SELECT f2();
+ERROR HY000: The target table v2 of the INSERT is not updatable
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+DROP VIEW v1, v2;
+DROP TABLE t1;
+End of 5.0 tests.

--- 1.153/mysql-test/t/view.test	2006-08-30 15:25:38 +04:00
+++ 1.154/mysql-test/t/view.test	2006-08-30 15:25:38 +04:00
@@ -2723,3 +2723,120 @@ DROP TABLE t1;
 --disable_warnings
 DROP VIEW IF EXISTS v1;
 --enable_warnings
+
+#
+# Bug #21261: Wrong access rights was required for an insert to a view
+#
+CREATE DATABASE bug21261DB;
+USE bug21261DB;
+CONNECT (root,localhost,root,,bug21261DB);
+CONNECTION root;
+
+CREATE TABLE t1 (x INT);
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT x FROM t1;
+GRANT INSERT, UPDATE ON v1 TO 'user21261'@'localhost';
+GRANT INSERT, UPDATE ON t1 TO 'user21261'@'localhost';
+CREATE TABLE t2 (y INT);
+GRANT SELECT ON t2 TO 'user21261'@'localhost';
+
+CONNECT (user21261, localhost, user21261,, bug21261DB);
+CONNECTION user21261;
+INSERT INTO v1 (x) VALUES (5);
+UPDATE v1 SET x=1;
+CONNECTION root;
+GRANT SELECT ON v1 TO 'user21261'@'localhost';
+GRANT SELECT ON t1 TO 'user21261'@'localhost';
+CONNECTION user21261;
+UPDATE v1,t2 SET x=1 WHERE x=y;
+CONNECTION root;
+SELECT * FROM t1;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'user21261'@'localhost';
+DROP USER 'user21261'@'localhost';
+DROP VIEW v1;
+DROP TABLE t1;
+DROP DATABASE bug21261DB;
+USE test;
+
+#
+# Bug #15950: NOW() optimized away in VIEWs
+#
+create table t1 (f1 datetime);
+create view v1 as select * from t1 where f1 between now() and now() + interval 1 minute;
+show create view v1;
+drop view v1;
+drop table t1;
+#
+# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
+#
+
+# Prepare.
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP VIEW IF EXISTS v1;
+DROP VIEW IF EXISTS v2;
+--enable_warnings
+
+CREATE TABLE t1(a INT, b INT);
+
+--error ER_WRONG_STRING_LENGTH
+CREATE DEFINER=1234567890abcdefGHIKL@localhost
+  VIEW v1 AS SELECT a FROM t1;
+
+--error ER_WRONG_STRING_LENGTH
+CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
+  VIEW v2 AS SELECT b FROM t1;
+
+# Cleanup.
+
+DROP TABLE t1;
+
+
+#
+# BUG#17591: Updatable view not possible with trigger or stored
+# function 
+#
+# During prelocking phase we didn't update lock type of view tables,
+# hence READ lock was always requested.
+#
+--disable_warnings
+DROP FUNCTION IF EXISTS f1;
+DROP FUNCTION IF EXISTS f2;
+DROP VIEW IF EXISTS v1, v2;
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (i INT);
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+delimiter |;
+CREATE FUNCTION f1() RETURNS INT
+BEGIN
+  INSERT INTO v1 VALUES (0);
+  RETURN 0;
+END |
+delimiter ;|
+
+SELECT f1();
+
+CREATE ALGORITHM=TEMPTABLE VIEW v2 AS SELECT * FROM t1;
+
+delimiter |;
+CREATE FUNCTION f2() RETURNS INT
+BEGIN
+  INSERT INTO v2 VALUES (0);
+  RETURN 0;
+END |
+delimiter ;|
+
+--error ER_NON_UPDATABLE_TABLE
+SELECT f2();
+
+DROP FUNCTION f1;
+DROP FUNCTION f2;
+DROP VIEW v1, v2;
+DROP TABLE t1;
+
+
+--echo End of 5.0 tests.

--- 1.33/sql/item_row.cc	2006-08-30 15:25:38 +04:00
+++ 1.34/sql/item_row.cc	2006-08-30 15:25:38 +04:00
@@ -156,12 +156,22 @@ bool Item_row::walk(Item_processor proce
 
 Item *Item_row::transform(Item_transformer transformer, byte *arg)
 {
+  DBUG_ASSERT(!current_thd->is_stmt_prepare());
+
   for (uint i= 0; i < arg_count; i++)
   {
     Item *new_item= items[i]->transform(transformer, arg);
     if (!new_item)
       return 0;
-    items[i]= new_item;
+
+    /*
+      THD::change_item_tree() should be called only if the tree was
+      really transformed, i.e. when a new item has been created.
+      Otherwise we'll be allocating a lot of unnecessary memory for
+      change records at each execution.
+    */
+    if (items[i] != new_item)
+      current_thd->change_item_tree(&items[i], new_item);
   }
   return (this->*transformer)(arg);
 }

--- 1.128/sql/item_subselect.cc	2006-08-30 15:25:38 +04:00
+++ 1.129/sql/item_subselect.cc	2006-08-30 15:25:38 +04:00
@@ -1141,24 +1141,23 @@ Item_in_subselect::row_value_transformer
         DBUG_RETURN(RES_ERROR);
       Item *item_eq=
         new Item_func_eq(new
-                         Item_direct_ref(&select_lex->context,
-                                         (*optimizer->get_cache())->
-                                         addr(i),
-                                         (char *)"<no matter>",
-                                         (char *)in_left_expr_name),
+                         Item_ref(&select_lex->context,
+                                  (*optimizer->get_cache())->
+                                  addr(i),
+                                  (char *)"<no matter>",
+                                  (char *)in_left_expr_name),
                          new
-                         Item_direct_ref(&select_lex->context,
-                                         select_lex->ref_pointer_array + i,
-                                         (char *)"<no matter>",
-                                         (char *)"<list ref>")
+                         Item_ref(&select_lex->context,
+                                  select_lex->ref_pointer_array + i,
+                                  (char *)"<no matter>",
+                                  (char *)"<list ref>")
                         );
       Item *item_isnull=
         new Item_func_isnull(new
-                             Item_direct_ref(&select_lex->context,
-                                             select_lex->
-                                             ref_pointer_array+i,
-                                             (char *)"<no matter>",
-                                             (char *)"<list ref>")
+                             Item_ref(&select_lex->context,
+                                      select_lex->ref_pointer_array+i,
+                                      (char *)"<no matter>",
+                                      (char *)"<list ref>")
                             );
       having_item=
         and_items(having_item,
@@ -1168,11 +1167,11 @@ Item_in_subselect::row_value_transformer
                   new
                   Item_is_not_null_test(this,
                                         new
-                                        Item_direct_ref(&select_lex->context,
-                                                        select_lex->
-                                                        ref_pointer_array + i,
-                                                        (char *)"<no matter>",
-                                                        (char *)"<list ref>")
+                                        Item_ref(&select_lex->context,
+                                                 select_lex->
+                                                 ref_pointer_array + i,
+                                                 (char *)"<no matter>",
+                                                 (char *)"<list ref>")
                                        )
                  );
       item_having_part2->top_level_item();
@@ -1228,11 +1227,11 @@ Item_in_subselect::row_value_transformer
                     new
                     Item_is_not_null_test(this,
                                           new
-                                          Item_direct_ref(&select_lex->context,
-                                                          select_lex->
-                                                          ref_pointer_array + i,
-                                                          (char *)"<no matter>",
-                                                          (char *)"<list ref>")
+                                          Item_ref(&select_lex->context,
+                                                   select_lex->
+                                                   ref_pointer_array + i,
+                                                   (char *)"<no matter>",
+                                                   (char *)"<list ref>")
                                          )
                   );
         item_isnull= new

--- 1.45/mysql-test/r/trigger.result	2006-08-30 15:25:38 +04:00
+++ 1.46/mysql-test/r/trigger.result	2006-08-30 15:25:38 +04:00
@@ -626,12 +626,51 @@ Trigger	Event	Table	Statement	Timing	Cre
 t1_bi	INSERT	t1	set new.a = '2004-01-00'	BEFORE	#		root@localhost
 drop table t1;
 create table t1 (id int);
+create trigger t1_ai after insert on t1 for each row reset query cache;
+ERROR 0A000: RESET is not allowed in stored function or trigger
+create trigger t1_ai after insert on t1 for each row reset master;
+ERROR 0A000: RESET is not allowed in stored function or trigger
+create trigger t1_ai after insert on t1 for each row reset slave;
+ERROR 0A000: RESET is not allowed in stored function or trigger
+create trigger t1_ai after insert on t1 for each row flush hosts;
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+create trigger t1_ai after insert on t1 for each row flush tables with read lock;
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+create trigger t1_ai after insert on t1 for each row flush logs;
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+create trigger t1_ai after insert on t1 for each row flush status;
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+create trigger t1_ai after insert on t1 for each row flush slave;
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+create trigger t1_ai after insert on t1 for each row flush master;
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+create trigger t1_ai after insert on t1 for each row flush des_key_file;
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+create trigger t1_ai after insert on t1 for each row flush user_resources;
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
 create trigger t1_ai after insert on t1 for each row flush tables;
 ERROR 0A000: FLUSH is not allowed in stored function or trigger
 create trigger t1_ai after insert on t1 for each row flush privileges;
 ERROR 0A000: FLUSH is not allowed in stored function or trigger
-create procedure p1() flush tables;
+drop procedure if exists p1;
 create trigger t1_ai after insert on t1 for each row call p1();
+create procedure p1() flush tables;
+insert into t1 values (0);
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+drop procedure p1;
+create procedure p1() reset query cache;
+insert into t1 values (0);
+ERROR 0A000: RESET is not allowed in stored function or trigger
+drop procedure p1;
+create procedure p1() reset master;
+insert into t1 values (0);
+ERROR 0A000: RESET is not allowed in stored function or trigger
+drop procedure p1;
+create procedure p1() reset slave;
+insert into t1 values (0);
+ERROR 0A000: RESET is not allowed in stored function or trigger
+drop procedure p1;
+create procedure p1() flush hosts;
 insert into t1 values (0);
 ERROR 0A000: FLUSH is not allowed in stored function or trigger
 drop procedure p1;
@@ -639,6 +678,38 @@ create procedure p1() flush privileges;
 insert into t1 values (0);
 ERROR 0A000: FLUSH is not allowed in stored function or trigger
 drop procedure p1;
+create procedure p1() flush tables with read lock;
+insert into t1 values (0);
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+drop procedure p1;
+create procedure p1() flush tables;
+insert into t1 values (0);
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+drop procedure p1;
+create procedure p1() flush logs;
+insert into t1 values (0);
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+drop procedure p1;
+create procedure p1() flush status;
+insert into t1 values (0);
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+drop procedure p1;
+create procedure p1() flush slave;
+insert into t1 values (0);
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+drop procedure p1;
+create procedure p1() flush master;
+insert into t1 values (0);
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+drop procedure p1;
+create procedure p1() flush des_key_file;
+insert into t1 values (0);
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+drop procedure p1;
+create procedure p1() flush user_resources;
+insert into t1 values (0);
+ERROR 0A000: FLUSH is not allowed in stored function or trigger
+drop procedure p1;
 drop table t1;
 create table t1 (id int, data int, username varchar(16));
 insert into t1 (id, data) values (1, 0);
@@ -1089,4 +1160,17 @@ begin
 set @a:= 1;
 end|
 ERROR HY000: Triggers can not be created on system tables
+use test|
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+CREATE TABLE t1(c INT);
+CREATE TABLE t2(c INT);
+CREATE DEFINER=1234567890abcdefGHIKL@localhost
+TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a = 1;
+ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
+CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
+TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW SET @a = 2;
+ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
+DROP TABLE t1;
+DROP TABLE t2;
 End of 5.0 tests

--- 1.49/mysql-test/t/trigger.test	2006-08-30 15:25:38 +04:00
+++ 1.50/mysql-test/t/trigger.test	2006-08-30 15:25:38 +04:00
@@ -651,17 +651,105 @@ drop table t1;
 # of functions and triggers.
 create table t1 (id int);
 --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row reset query cache;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row reset master;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row reset slave;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row flush hosts;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row flush tables with read lock;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row flush logs;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row flush status;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row flush slave;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row flush master;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row flush des_key_file;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+create trigger t1_ai after insert on t1 for each row flush user_resources;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
 create trigger t1_ai after insert on t1 for each row flush tables;
 --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
 create trigger t1_ai after insert on t1 for each row flush privileges;
-create procedure p1() flush tables;
+--disable_warnings
+drop procedure if exists p1;
+--enable_warnings
+
 create trigger t1_ai after insert on t1 for each row call p1();
+create procedure p1() flush tables;
 --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
 insert into t1 values (0);
+
+drop procedure p1;
+create procedure p1() reset query cache;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+
+drop procedure p1;
+create procedure p1() reset master;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+
+drop procedure p1;
+create procedure p1() reset slave;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+
+drop procedure p1;
+create procedure p1() flush hosts;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+
 drop procedure p1;
 create procedure p1() flush privileges;
 --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
 insert into t1 values (0);
+
+drop procedure p1;
+create procedure p1() flush tables with read lock;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+
+drop procedure p1;
+create procedure p1() flush tables;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+
+drop procedure p1;
+create procedure p1() flush logs;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+
+drop procedure p1;
+create procedure p1() flush status;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+
+drop procedure p1;
+create procedure p1() flush slave;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+
+drop procedure p1;
+create procedure p1() flush master;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+
+drop procedure p1;
+create procedure p1() flush des_key_file;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+
+drop procedure p1;
+create procedure p1() flush user_resources;
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+insert into t1 values (0);
+
 drop procedure p1;
 drop table t1;
 
@@ -1301,6 +1389,36 @@ create trigger wont_work after update on
 begin
  set @a:= 1;
 end|
+use test|
 delimiter ;|
+
+
+#
+# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
+#
+
+# Prepare.
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+--enable_warnings
+
+CREATE TABLE t1(c INT);
+CREATE TABLE t2(c INT);
+
+--error ER_WRONG_STRING_LENGTH
+CREATE DEFINER=1234567890abcdefGHIKL@localhost
+  TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a = 1;
+
+--error ER_WRONG_STRING_LENGTH
+CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
+  TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW SET @a = 2;
+
+# Cleanup.
+
+DROP TABLE t1;
+DROP TABLE t2;
+
 
 --echo End of 5.0 tests

--- 1.22/sql/sql_trigger.h	2006-08-30 15:25:38 +04:00
+++ 1.23/sql/sql_trigger.h	2006-08-30 15:25:38 +04:00
@@ -92,10 +92,8 @@ public:
   }
   ~Table_triggers_list();
 
-  bool create_trigger(THD *thd, TABLE_LIST *table,
-                      LEX_STRING *definer_user,
-                      LEX_STRING *definer_host);
-  bool drop_trigger(THD *thd, TABLE_LIST *table);
+  bool create_trigger(THD *thd, TABLE_LIST *table, String *stmt_query);
+  bool drop_trigger(THD *thd, TABLE_LIST *table, String *stmt_query);
   bool process_triggers(THD *thd, trg_event_type event,
                         trg_action_time_type time_type,
                         bool old_row_is_record1);

--- 1.4/mysql-test/lib/mtr_io.pl	2006-08-30 15:25:38 +04:00
+++ 1.5/mysql-test/lib/mtr_io.pl	2006-08-30 15:25:38 +04:00
@@ -20,13 +20,39 @@ sub mtr_lastlinefromfile($);
 ##############################################################################
 
 sub mtr_get_pid_from_file ($) {
-  my $file=  shift;
+  my $pid_file_path=  shift;
+  my $TOTAL_ATTEMPTS= 30;
+  my $timeout= 1;
 
-  open(FILE,"<",$file) or mtr_error("can't open file \"$file\": $!");
-  my $pid=  <FILE>;
-  chomp($pid);
-  close FILE;
-  return $pid;
+  # We should read from the file until we get correct pid. As it is
+  # stated in BUG#21884, pid file can be empty at some moment. So, we should
+  # read it until we get valid data.
+
+  for (my $cur_attempt= 1; $cur_attempt <= $TOTAL_ATTEMPTS; ++$cur_attempt)
+  {
+    mtr_debug("Reading pid file '$pid_file_path' " .
+              "($cur_attempt of $TOTAL_ATTEMPTS)...");
+
+    open(FILE, '<', $pid_file_path)
+      or mtr_error("can't open file \"$pid_file_path\": $!");
+
+    my $pid= <FILE>;
+
+    chomp($pid) if defined $pid;
+
+    close FILE;
+
+    return $pid if defined $pid && $pid ne '';
+
+    mtr_debug("Pid file '$pid_file_path' is empty. " .
+              "Sleeping $timeout second(s)...");
+
+    sleep(1);
+  }
+
+  mtr_error("Pid file '$pid_file_path' is corrupted. " .
+            "Can not retrieve PID in " .
+            ($timeout * $TOTAL_ATTEMPTS) . " seconds.");
 }
 
 sub mtr_get_opts_from_file ($) {

--- 1.45/mysql-test/lib/mtr_process.pl	2006-08-30 15:25:38 +04:00
+++ 1.46/mysql-test/lib/mtr_process.pl	2006-08-30 15:25:38 +04:00
@@ -25,7 +25,28 @@ sub sleep_until_file_created ($$$);
 sub mtr_kill_processes ($);
 sub mtr_ping_with_timeout($);
 sub mtr_ping_port ($);
-sub mtr_kill_process ($$$);
+
+# Private IM-related operations.
+
+sub mtr_im_kill_process ($$$$);
+sub mtr_im_load_pids ($);
+sub mtr_im_terminate ($);
+sub mtr_im_check_alive ($);
+sub mtr_im_check_main_alive ($);
+sub mtr_im_check_angel_alive ($);
+sub mtr_im_check_mysqlds_alive ($);
+sub mtr_im_check_mysqld_alive ($$);
+sub mtr_im_cleanup ($);
+sub mtr_im_rm_file ($);
+sub mtr_im_errlog ($);
+sub mtr_im_kill ($);
+sub mtr_im_wait_for_connection ($$$);
+sub mtr_im_wait_for_mysqld($$$);
+
+# Public IM-related operations.
+
+sub mtr_im_start ($$);
+sub mtr_im_stop ($);
 
 # static in C
 sub spawn_impl ($$$$$$$$);
@@ -335,16 +356,27 @@ sub mtr_process_exit_status {
 # kill IM manager first, else it will restart the servers
 sub mtr_kill_leftovers () {
 
+  mtr_debug("mtr_kill_leftovers(): started.");
+
+  mtr_im_stop($::instance_manager);
+
+  # Start shutdown of masters and slaves. Don't touch IM-managed mysqld
+  # instances -- they should be stopped by mtr_im_stop().
+
+  mtr_debug("Shutting down mysqld-instances...");
+
   my @kill_pids;
   my %admin_pids;
-  my $pid;
 
-  #Start shutdown of instance_managers, masters and slaves
-  foreach my $srv ($::instance_manager,
-		   @{$::instance_manager->{'instances'}},
-		   @{$::master},@{$::slave})
+  foreach my $srv (@{$::master}, @{$::slave})
   {
-    $pid= mtr_mysqladmin_start($srv, "shutdown", 70);
+    mtr_debug("  - mysqld " .
+              "(pid: $srv->{pid}; " .
+              "pid file: '$srv->{path_pid}'; " .
+              "socket: '$srv->{path_sock}'; ".
+              "port: $srv->{port})");
+
+    my $pid= mtr_mysqladmin_start($srv, "shutdown", 70);
 
     # Save the pid of the mysqladmin process
     $admin_pids{$pid}= 1;
@@ -358,10 +390,17 @@ sub mtr_kill_leftovers () {
     $srv->{'pid'}= 0; # Assume we are done with it
   }
 
-  # Start shutdown of clusters
+  # Start shutdown of clusters.
+
+  mtr_debug("Shutting down cluster...");
+
   foreach my $cluster (@{$::clusters})
   {
-    $pid= mtr_ndbmgm_start($cluster, "shutdown");
+    mtr_debug("  - cluster " .
+              "(pid: $cluster->{pid}; " .
+              "pid file: '$cluster->{path_pid})");
+
+    my $pid= mtr_ndbmgm_start($cluster, "shutdown");
 
     # Save the pid of the ndb_mgm process
     $admin_pids{$pid}= 1;
@@ -376,13 +415,16 @@ sub mtr_kill_leftovers () {
 
     foreach my $ndbd (@{$cluster->{'ndbds'}})
     {
+      mtr_debug("    - ndbd " .
+                "(pid: $ndbd->{pid}; " .
+                "pid file: '$ndbd->{path_pid})");
+
       push(@kill_pids,{
 		       pid      => $ndbd->{'pid'},
 		       pidfile  => $ndbd->{'path_pid'},
 		      });
       $ndbd->{'pid'}= 0; # Assume we are done with it
     }
-
   }
 
   # Wait for all the admin processes to complete
@@ -411,6 +453,8 @@ sub mtr_kill_leftovers () {
   # FIXME $path_run_dir or something
   my $rundir= "$::opt_vardir/run";
 
+  mtr_debug("Processing PID files in directory '$rundir'...");
+
   if ( -d $rundir )
   {
     opendir(RUNDIR, $rundir)
@@ -424,8 +468,12 @@ sub mtr_kill_leftovers () {
 
       if ( -f $pidfile )
       {
+        mtr_debug("Processing PID file: '$pidfile'...");
+
         my $pid= mtr_get_pid_from_file($pidfile);
 
+        mtr_debug("Got pid: $pid from file '$pidfile'");
+
         # Race, could have been removed between I tested with -f
         # and the unlink() below, so I better check again with -f
 
@@ -436,14 +484,24 @@ sub mtr_kill_leftovers () {
 
         if ( $::glob_cygwin_perl or kill(0, $pid) )
         {
+          mtr_debug("There is process with pid $pid -- scheduling for kill.");
           push(@pids, $pid);            # We know (cygwin guess) it exists
         }
+        else
+        {
+          mtr_debug("There is no process with pid $pid -- skipping.");
+        }
       }
     }
     closedir(RUNDIR);
 
     if ( @pids )
     {
+      mtr_debug("Killing the following processes with PID files: " .
+                join(' ', @pids) . "...");
+
+      start_reap_all();
+
       if ( $::glob_cygwin_perl )
       {
         # We have no (easy) way of knowing the Cygwin controlling
@@ -457,6 +515,7 @@ sub mtr_kill_leftovers () {
         my $retries= 10;                    # 10 seconds
         do
         {
+          mtr_debug("Sending SIGKILL to pids: " . join(' ', @pids));
           kill(9, @pids);
           mtr_report("Sleep 1 second waiting for processes to die");
           sleep(1)                      # Wait one second
@@ -467,12 +526,20 @@ sub mtr_kill_leftovers () {
           mtr_warning("can't kill process(es) " . join(" ", @pids));
         }
       }
+
+      stop_reap_all();
     }
   }
+  else
+  {
+    mtr_debug("Directory for PID files ($rundir) does not exist.");
+  }
 
   # We may have failed everything, but we now check again if we have
   # the listen ports free to use, and if they are free, just go for it.
 
+  mtr_debug("Checking known mysqld servers...");
+
   foreach my $srv ( @kill_pids )
   {
     if ( defined $srv->{'port'} and mtr_ping_port($srv->{'port'}) )
@@ -480,6 +547,8 @@ sub mtr_kill_leftovers () {
       mtr_warning("can't kill old process holding port $srv->{'port'}");
     }
   }
+
+  mtr_debug("mtr_kill_leftovers(): finished.");
 }
 
 
@@ -736,6 +805,9 @@ sub mtr_ping_with_timeout($) {
   my $res= 1;                           # If we just fall through, we are done
                                         # in the sense that the servers don't
                                         # listen to their ports any longer
+
+  mtr_debug("Waiting for mysqld servers to stop...");
+
  TIME:
   while ( $timeout-- )
   {
@@ -763,7 +835,14 @@ sub mtr_ping_with_timeout($) {
     last;                               # If we got here, we are done
   }
 
-  $timeout or mtr_report("At least one server is still listening to its port");
+  if ($res)
+  {
+    mtr_debug("mtr_ping_with_timeout(): All mysqld instances are down.");
+  }
+  else
+  {
+    mtr_report("mtr_ping_with_timeout(): At least one server is alive.");
+  }
 
   return $res;
 }
@@ -946,6 +1025,9 @@ sub mtr_ping_port ($) {
   {
     mtr_error("can't create socket: $!");
   }
+
+  mtr_debug("Pinging server (port: $port)...");
+
   if ( connect(SOCK, $paddr) )
   {
     close(SOCK);                        # FIXME check error?
@@ -1016,34 +1098,12 @@ sub mtr_kill_processes ($) {
   {
     foreach my $sig (15, 9)
     {
-      last if mtr_kill_process($pid, $sig, 10);
+      last if mtr_im_kill_process($pid, $sig, 10);
     }
   }
 }
 
 
-sub mtr_kill_process ($$$) {
-  my $pid= shift;
-  my $signal= shift;
-  my $timeout= shift; # Seconds to wait for process
-  my $max_loop= $timeout*10; # Sleeping 0.1 between each kill attempt
-
-  for (my $cur_attempt= 1; $cur_attempt <= $max_loop; ++$cur_attempt)
-  {
-    mtr_debug("Sending $signal to $pid...");
-
-    kill($signal, $pid);
-
-    last unless kill (0, $pid) and $max_loop--;
-
-    mtr_verbose("Sleep 0.1 second waiting for processes $pid to die");
-
-    select(undef, undef, undef, 0.1);
-  }
-
-  return $max_loop;
-}
-
 ##############################################################################
 #
 #  When we exit, we kill off all children
@@ -1072,5 +1132,677 @@ sub mtr_exit ($) {
 
   exit($code);
 }
+
+##############################################################################
+#
+#  Instance Manager management routines.
+#
+##############################################################################
+
+sub mtr_im_kill_process ($$$) {
+  my $pid_lst= shift;
+  my $signal= shift;
+  my $timeout= shift;
+  my $total_attempts= $timeout * 10;
+
+  my %pids;
+
+  foreach my $pid (@{$pid_lst})
+  {
+    $pids{$pid}= 1;
+  }
+
+  for (my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt)
+  {
+    foreach my $pid (keys %pids)
+    {
+      mtr_debug("Sending $signal to $pid...");
+
+      kill($signal, $pid);
+
+      unless (kill (0, $pid))
+      {
+        mtr_debug("Process $pid died.");
+        delete $pids{$pid};
+      }
+    }
+
+    return if scalar keys %pids == 0;
+
+    mtr_debug("Sleeping 100ms waiting for processes to die...");
+
+    select(undef, undef, undef, 0.1);
+  }
+
+  mtr_debug("Process(es) " .
+            join(' ', keys %pids) .
+            " is still alive after $total_attempts " .
+            "of sending signal $signal.");
+}
+
+###########################################################################
+
+sub mtr_im_load_pids($) {
+  my $instance_manager= shift;
+
+  mtr_debug("Loading PID files...");
+
+  # Obtain mysqld-process pids.
+
+  my $instances = $instance_manager->{'instances'};
+
+  for (my $idx= 0; $idx < 2; ++$idx)
+  {
+    mtr_debug("IM-guarded mysqld[$idx] PID file: '" .
+              $instances->[$idx]->{'path_pid'} . "'.");
+
+    my $mysqld_pid;
+
+    if (-r $instances->[$idx]->{'path_pid'})
+    {
+      $mysqld_pid= mtr_get_pid_from_file($instances->[$idx]->{'path_pid'});
+      mtr_debug("IM-guarded mysqld[$idx] PID: $mysqld_pid.");
+    }
+    else
+    {
+      $mysqld_pid= undef;
+      mtr_debug("IM-guarded mysqld[$idx]: no PID file.");
+    }
+
+    $instances->[$idx]->{'pid'}= $mysqld_pid;
+  }
+
+  # Re-read Instance Manager PIDs from the file, since during tests Instance
+  # Manager could have been restarted, so its PIDs could have been changed.
+
+  #   - IM-main
+
+  mtr_debug("IM-main PID file: '$instance_manager->{path_pid}'.");
+
+  if (-f $instance_manager->{'path_pid'})
+  {
+    $instance_manager->{'pid'} =
+      mtr_get_pid_from_file($instance_manager->{'path_pid'});
+
+    mtr_debug("IM-main PID: $instance_manager->{pid}.");
+  }
+  else
+  {
+    mtr_debug("IM-main: no PID file.");
+    $instance_manager->{'pid'}= undef;
+  }
+
+  #   - IM-angel
+
+  mtr_debug("IM-angel PID file: '$instance_manager->{path_angel_pid}'.");
+
+  if (-f $instance_manager->{'path_angel_pid'})
+  {
+    $instance_manager->{'angel_pid'} =
+      mtr_get_pid_from_file($instance_manager->{'path_angel_pid'});
+
+    mtr_debug("IM-angel PID: $instance_manager->{'angel_pid'}.");
+  }
+  else
+  {
+    mtr_debug("IM-angel: no PID file.");
+    $instance_manager->{'angel_pid'} = undef;
+  }
+}
+
+###########################################################################
+
+sub mtr_im_terminate($) {
+  my $instance_manager= shift;
+
+  # Load pids from pid-files. We should do it first of all, because IM deletes
+  # them on shutdown.
+
+  mtr_im_load_pids($instance_manager);
+
+  mtr_debug("Shutting Instance Manager down...");
+
+  # Ignoring SIGCHLD so that all children could rest in peace.
+
+  start_reap_all();
+
+  # Send SIGTERM to IM-main.
+
+  if (defined $instance_manager->{'pid'})
+  {
+    mtr_debug("IM-main pid: $instance_manager->{pid}.");
+    mtr_debug("Stopping IM-main...");
+
+    mtr_im_kill_process([ $instance_manager->{'pid'} ], 'TERM', 10, 1);
+  }
+  else
+  {
+    mtr_debug("IM-main pid: n/a.");
+  }
+
+  # If IM-angel was alive, wait for it to die.
+
+  if (defined $instance_manager->{'angel_pid'})
+  {
+    mtr_debug("IM-angel pid: $instance_manager->{'angel_pid'}.");
+    mtr_debug("Waiting for IM-angel to die...");
+
+    my $total_attempts= 10;
+
+    for (my $cur_attempt=1; $cur_attempt <= $total_attempts; ++$cur_attempt)
+    {
+      unless (kill (0, $instance_manager->{'angel_pid'}))
+      {
+        mtr_debug("IM-angel died.");
+        last;
+      }
+
+      sleep(1);
+    }
+  }
+  else
+  {
+    mtr_debug("IM-angel pid: n/a.");
+  }
+
+  stop_reap_all();
+
+  # Re-load PIDs.
+
+  mtr_im_load_pids($instance_manager);
+}
+
+###########################################################################
+
+sub mtr_im_check_alive($) {
+  my $instance_manager= shift;
+
+  mtr_debug("Checking whether IM-components are alive...");
+
+  return 1 if mtr_im_check_main_alive($instance_manager);
+
+  return 1 if mtr_im_check_angel_alive($instance_manager);
+
+  return 1 if mtr_im_check_mysqlds_alive($instance_manager);
+
+  return 0;
+}
+
+###########################################################################
+
+sub mtr_im_check_main_alive($) {
+  my $instance_manager= shift;
+
+  # Check that the process, that we know to be IM's, is dead.
+
+  if (defined $instance_manager->{'pid'})
+  {
+    if (kill (0, $instance_manager->{'pid'}))
+    {
+      mtr_debug("IM-main (PID: $instance_manager->{pid}) is alive.");
+      return 1;
+    }
+    else
+    {
+      mtr_debug("IM-main (PID: $instance_manager->{pid}) is dead.");
+    }
+  }
+  else
+  {
+    mtr_debug("No PID file for IM-main.");
+  }
+
+  # Check that IM does not accept client connections.
+
+  if (mtr_ping_mysqld_server($instance_manager->{'port'}))
+  {
+    mtr_debug("IM-main (port: $instance_manager->{port}) " .
+              "is accepting connections.");
+
+    mtr_im_errlog("IM-main is accepting connections on port " .
+                  "$instance_manager->{port}, but there is no " .
+                  "process information.");
+    return 1;
+  }
+  else
+  {
+    mtr_debug("IM-main (port: $instance_manager->{port}) " .
+              "does not accept connections.");
+    return 0;
+  }
+}
+
+###########################################################################
+
+sub mtr_im_check_angel_alive($) {
+  my $instance_manager= shift;
+
+  # Check that the process, that we know to be the Angel, is dead.
+
+  if (defined $instance_manager->{'angel_pid'})
+  {
+    if (kill (0, $instance_manager->{'angel_pid'}))
+    {
+      mtr_debug("IM-angel (PID: $instance_manager->{angel_pid}) is alive.");
+      return 1;
+    }
+    else
+    {
+      mtr_debug("IM-angel (PID: $instance_manager->{angel_pid}) is dead.");
+      return 0;
+    }
+  }
+  else
+  {
+    mtr_debug("No PID file for IM-angel.");
+    return 0;
+  }
+}
+
+###########################################################################
+
+sub mtr_im_check_mysqlds_alive($) {
+  my $instance_manager= shift;
+
+  mtr_debug("Checking for IM-guarded mysqld instances...");
+
+  my $instances = $instance_manager->{'instances'};
+
+  for (my $idx= 0; $idx < 2; ++$idx)
+  {
+    mtr_debug("Checking mysqld[$idx]...");
+
+    return 1
+      if mtr_im_check_mysqld_alive($instance_manager, $instances->[$idx]);
+  }
+}
+
+###########################################################################
+
+sub mtr_im_check_mysqld_alive($$) {
+  my $instance_manager= shift;
+  my $mysqld_instance= shift;
+
+  # Check that the process is dead.
+
+  if (defined $instance_manager->{'pid'})
+  {
+    if (kill (0, $instance_manager->{'pid'}))
+    {
+      mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is alive.");
+      return 1;
+    }
+    else
+    {
+      mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is dead.");
+    }
+  }
+  else
+  {
+    mtr_debug("No PID file for mysqld instance.");
+  }
+
+  # Check that mysqld does not accept client connections.
+
+  if (mtr_ping_mysqld_server($mysqld_instance->{'port'}))
+  {
+    mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " .
+              "is accepting connections.");
+
+    mtr_im_errlog("Mysqld is accepting connections on port " .
+                  "$mysqld_instance->{port}, but there is no " .
+                  "process information.");
+    return 1;
+  }
+  else
+  {
+    mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " .
+              "does not accept connections.");
+    return 0;
+  }
+}
+
+###########################################################################
+
+sub mtr_im_cleanup($) {
+  my $instance_manager= shift;
+
+  mtr_im_rm_file($instance_manager->{'path_pid'});
+  mtr_im_rm_file($instance_manager->{'path_sock'});
+
+  mtr_im_rm_file($instance_manager->{'path_angel_pid'});
+
+  for (my $idx= 0; $idx < 2; ++$idx)
+  {
+    mtr_im_rm_file($instance_manager->{'instances'}->[$idx]->{'path_pid'});
+    mtr_im_rm_file($instance_manager->{'instances'}->[$idx]->{'path_sock'});
+  }
+}
+
+###########################################################################
+
+sub mtr_im_rm_file($)
+{
+  my $file_path= shift;
+
+  if (-f $file_path)
+  {
+    mtr_debug("Removing '$file_path'...");
+
+    mtr_warning("Can not remove '$file_path'.")
+      unless unlink($file_path);
+  }
+  else
+  {
+    mtr_debug("File '$file_path' does not exist already.");
+  }
+}
+
+###########################################################################
+
+sub mtr_im_errlog($) {
+  my $msg= shift;
+
+  # Complain in error log so that a warning will be shown.
+  # 
+  # TODO: unless BUG#20761 is fixed, we will print the warning to stdout, so
+  # that it can be seen on console and does not produce pushbuild error.
+
+  # my $errlog= "$opt_vardir/log/mysql-test-run.pl.err";
+  # 
+  # open (ERRLOG, ">>$errlog") ||
+  #   mtr_error("Can not open error log ($errlog)");
+  # 
+  # my $ts= localtime();
+  # print ERRLOG
+  #   "Warning: [$ts] $msg\n";
+  # 
+  # close ERRLOG;
+
+  my $ts= localtime();
+  print "Warning: [$ts] $msg\n";
+}
+
+###########################################################################
+
+sub mtr_im_kill($) {
+  my $instance_manager= shift;
+
+  # Re-load PIDs. That can be useful because some processes could have been
+  # restarted.
+
+  mtr_im_load_pids($instance_manager);
+
+  # Ignoring SIGCHLD so that all children could rest in peace.
+
+  start_reap_all();
+
+  # Kill IM-angel first of all.
+
+  if (defined $instance_manager->{'angel_pid'})
+  {
+    mtr_debug("Killing IM-angel (PID: $instance_manager->{angel_pid})...");
+    mtr_im_kill_process([ $instance_manager->{'angel_pid'} ], 'KILL', 10, 1)
+  }
+  else
+  {
+    mtr_debug("IM-angel is dead.");
+  }
+
+  # Re-load PIDs again.
+
+  mtr_im_load_pids($instance_manager);
+
+  # Kill IM-main.
+  
+  if (defined $instance_manager->{'pid'})
+  {
+    mtr_debug("Killing IM-main (PID: $instance_manager->pid})...");
+    mtr_im_kill_process([ $instance_manager->{'pid'} ], 'KILL', 10, 1);
+  }
+  else
+  {
+    mtr_debug("IM-main is dead.");
+  }
+
+  # Re-load PIDs again.
+
+  mtr_im_load_pids($instance_manager);
+
+  # Kill guarded mysqld instances.
+
+  my @mysqld_pids;
+
+  mtr_debug("Collecting PIDs of mysqld instances to kill...");
+
+  for (my $idx= 0; $idx < 2; ++$idx)
+  {
+    my $pid= $instance_manager->{'instances'}->[$idx]->{'pid'};
+
+    next unless defined $pid;
+
+    mtr_debug("  - IM-guarded mysqld[$idx] PID: $pid.");
+
+    push (@mysqld_pids, $pid);
+  }
+
+  if (scalar @mysqld_pids > 0)
+  {
+    mtr_debug("Killing IM-guarded mysqld instances...");
+    mtr_im_kill_process(\@mysqld_pids, 'KILL', 10, 1);
+  }
+
+  # That's all.
+
+  stop_reap_all();
+}
+
+##############################################################################
+
+sub mtr_im_wait_for_connection($$$) {
+  my $instance_manager= shift;
+  my $total_attempts= shift;
+  my $connect_timeout= shift;
+
+  mtr_debug("Waiting for IM on port $instance_manager->{port} " .
+            "to start accepting connections...");
+
+  for (my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt)
+  {
+    mtr_debug("Trying to connect to IM ($cur_attempt of $total_attempts)...");
+
+    if (mtr_ping_mysqld_server($instance_manager->{'port'}))
+    {
+      mtr_debug("IM is accepting connections " .
+                "on port $instance_manager->{port}.");
+      return 1;
+    }
+
+    mtr_debug("Sleeping $connect_timeout...");
+    sleep($connect_timeout);
+  }
+
+  mtr_debug("IM does not accept connections " .
+            "on port $instance_manager->{port} after " .
+            ($total_attempts * $connect_timeout) . " seconds.");
+
+  return 0;
+}
+
+##############################################################################
+
+sub mtr_im_wait_for_mysqld($$$) {
+  my $mysqld= shift;
+  my $total_attempts= shift;
+  my $connect_timeout= shift;
+
+  mtr_debug("Waiting for IM-guarded mysqld on port $mysqld->{port} " .
+            "to start accepting connections...");
+
+  for (my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt)
+  {
+    mtr_debug("Trying to connect to mysqld " .
+              "($cur_attempt of $total_attempts)...");
+
+    if (mtr_ping_mysqld_server($mysqld->{'port'}))
+    {
+      mtr_debug("Mysqld is accepting connections " .
+                "on port $mysqld->{port}.");
+      return 1;
+    }
+
+    mtr_debug("Sleeping $connect_timeout...");
+    sleep($connect_timeout);
+  }
+
+  mtr_debug("Mysqld does not accept connections " .
+            "on port $mysqld->{port} after " .
+            ($total_attempts * $connect_timeout) . " seconds.");
+
+  return 0;
+}
+
+##############################################################################
+
+sub mtr_im_start($$) {
+  my $instance_manager = shift;
+  my $opts = shift;
+
+  mtr_debug("Starting Instance Manager...");
+
+  my $args;
+  mtr_init_args(\$args);
+  mtr_add_arg($args, "--defaults-file=%s",
+              $instance_manager->{'defaults_file'});
+
+  foreach my $opt (@{$opts})
+  {
+    mtr_add_arg($args, $opt);
+  }
+
+  $instance_manager->{'pid'} =
+    mtr_spawn(
+      $::exe_im,                        # path to the executable
+      $args,                            # cmd-line args
+      '',                               # stdin
+      $instance_manager->{'path_log'},  # stdout
+      $instance_manager->{'path_err'},  # stderr
+      '',                               # pid file path (not used)
+      { append_log_file => 1 }          # append log files
+      );
+
+  if ( ! $instance_manager->{'pid'} )
+  {
+    mtr_report('Could not start Instance Manager');
+    return;
+  }
+
+  # Instance Manager can be run in daemon mode. In this case, it creates
+  # several processes and the parent process, created by mtr_spawn(), exits just
+  # after start. So, we have to obtain Instance Manager PID from the PID file.
+
+  if ( ! sleep_until_file_created(
+                                  $instance_manager->{'path_pid'},
+                                  $instance_manager->{'start_timeout'},
+                                  -1)) # real PID is still unknown
+  {
+    mtr_report("Instance Manager PID file is missing");
+    return;
+  }
+
+  $instance_manager->{'pid'} =
+    mtr_get_pid_from_file($instance_manager->{'path_pid'});
+
+  mtr_debug("Instance Manager started. PID: $instance_manager->{pid}.");
+
+  # Wait until we can connect to IM.
+
+  my $IM_CONNECT_TIMEOUT= 30;
+
+  unless (mtr_im_wait_for_connection($instance_manager,
+                                     $IM_CONNECT_TIMEOUT, 1))
+  {
+    mtr_debug("Can not connect to Instance Manager " .
+              "in $IM_CONNECT_TIMEOUT seconds after start.");
+    mtr_debug("Aborting test suite...");
+
+    mtr_kill_leftovers();
+
+    mtr_error("Can not connect to Instance Manager " .
+              "in $IM_CONNECT_TIMEOUT seconds after start.");
+  }
+
+  # Wait until we can connect to guarded mysqld-instances
+  # (in other words -- wait for IM to start guarded instances).
+
+  for (my $idx= 0; $idx < 2; ++$idx)
+  {
+    my $mysqld= $instance_manager->{'instances'}->[$idx];
+
+    next if exists $mysqld->{'nonguarded'};
+
+    mtr_debug("Waiting for mysqld[$idx] to start...");
+
+    unless (mtr_im_wait_for_mysqld($mysqld, 30, 1))
+    {
+      mtr_debug("Can not connect to mysqld[$idx] " .
+                "in $IM_CONNECT_TIMEOUT seconds after start.");
+      mtr_debug("Aborting test suite...");
+
+      mtr_kill_leftovers();
+
+      mtr_error("Can not connect to mysqld[$idx] " .
+                "in $IM_CONNECT_TIMEOUT seconds after start.");
+    }
+
+    mtr_debug("mysqld[$idx] started.");
+  }
+
+  mtr_debug("Instance Manager started.");
+}
+
+##############################################################################
+
+sub mtr_im_stop($) {
+  my $instance_manager= shift;
+
+  mtr_debug("Stopping Instance Manager...");
+
+  # Try graceful shutdown.
+
+  mtr_im_terminate($instance_manager);
+
+  # Check that all processes died.
+
+  unless (mtr_im_check_alive($instance_manager))
+  {
+    mtr_debug("Instance Manager has been stopped successfully.");
+    mtr_im_cleanup($instance_manager);
+    return 1;
+  }
+
+  # Instance Manager don't want to die. We should kill it.
+
+  mtr_im_errlog("Instance Manager did not shutdown gracefully.");
+
+  mtr_im_kill($instance_manager);
+
+  # Check again that all IM-related processes have been killed.
+
+  my $im_is_alive= mtr_im_check_alive($instance_manager);
+
+  mtr_im_cleanup($instance_manager);
+
+  if ($im_is_alive)
+  {
+    mtr_error("Can not kill Instance Manager or its children.");
+    return 0;
+  }
+
+  mtr_debug("Instance Manager has been killed successfully.");
+  return 1;
+}
+
+###########################################################################
 
 1;

--- 1.153/mysql-test/mysql-test-run.pl	2006-08-30 15:25:38 +04:00
+++ 1.154/mysql-test/mysql-test-run.pl	2006-08-30 15:25:38 +04:00
@@ -344,7 +344,7 @@ sub snapshot_setup ();
 sub executable_setup ();
 sub environment_setup ();
 sub kill_running_server ();
-sub kill_and_cleanup ();
+sub cleanup_stale_files ();
 sub check_ssl_support ();
 sub check_running_as_root();
 sub check_ndbcluster_support ();
@@ -368,8 +368,6 @@ sub ndb_mgmd_start ($);
 sub mysqld_start ($$$);
 sub mysqld_arguments ($$$$$);
 sub stop_all_servers ();
-sub im_start ($$);
-sub im_stop ($$);
 sub run_mysqltest ($);
 sub usage ($);
 
@@ -1454,14 +1452,13 @@ sub kill_running_server () {
 
     mtr_report("Killing Possible Leftover Processes");
     mkpath("$opt_vardir/log"); # Needed for mysqladmin log
+
     mtr_kill_leftovers();
 
    }
 }
 
-sub kill_and_cleanup () {
-
-  kill_running_server ();
+sub cleanup_stale_files () {
 
   mtr_report("Removing Stale Files");
 
@@ -1999,13 +1996,11 @@ sub run_suite () {
 sub initialize_servers () {
   if ( ! $glob_use_running_server )
   {
-    if ( $opt_start_dirty )
-    {
-      kill_running_server();
-    }
-    else
+    kill_running_server();
+
+    unless ( $opt_start_dirty )
     {
-      kill_and_cleanup();
+      cleanup_stale_files();
       mysql_install_db();
       if ( $opt_force )
       {
@@ -2397,10 +2392,9 @@ sub run_testcase ($) {
   # Stop Instance Manager if we are processing an IM-test case.
   # ----------------------------------------------------------------------
 
-  if ( ! $glob_use_running_server and $tinfo->{'component_id'} eq 'im' and
-       $instance_manager->{'pid'} )
+  if ( ! $glob_use_running_server and $tinfo->{'component_id'} eq 'im' )
   {
-    im_stop($instance_manager, $tinfo->{'name'});
+    mtr_im_stop($instance_manager, $tinfo->{'name'});
   }
 }
 
@@ -2937,11 +2931,8 @@ sub stop_all_servers () {
 
   print  "Stopping All Servers\n";
 
-  if ( $instance_manager->{'pid'} )
-  {
-    print  "Shutting-down Instance Manager\n";
-    im_stop($instance_manager, "stop_all_servers");
-  }
+  print  "Shutting-down Instance Manager\n";
+  mtr_im_stop($instance_manager, "stop_all_servers");
 
   my %admin_pids; # hash of admin processes that requests shutdown
   my @kill_pids;  # list of processes to shutdown/kill
@@ -3332,7 +3323,7 @@ sub run_testcase_start_servers($) {
 
     im_create_defaults_file($instance_manager);
 
-    im_start($instance_manager, $tinfo->{im_opts});
+    mtr_im_start($instance_manager, $tinfo->{im_opts});
   }
 
   # ----------------------------------------------------------------------
@@ -3395,236 +3386,6 @@ sub run_testcase_start_servers($) {
     }
   }
 }
-
-
-##############################################################################
-#
-#  Instance Manager management routines.
-#
-##############################################################################
-
-sub im_start($$) {
-  my $instance_manager = shift;
-  my $opts = shift;
-
-  my $args;
-  mtr_init_args(\$args);
-  mtr_add_arg($args, "--defaults-file=%s",
-              $instance_manager->{'defaults_file'});
-
-  if ( $opt_debug )
-  {
-    mtr_add_arg($args, "--debug=d:t:i:A,%s/log/im.trace",
-                $opt_vardir_trace);
-  }
-
-  foreach my $opt (@{$opts})
-  {
-    mtr_add_arg($args, $opt);
-  }
-
-  $instance_manager->{'pid'} =
-    mtr_spawn(
-      $exe_im,                          # path to the executable
-      $args,                            # cmd-line args
-      '',                               # stdin
-      $instance_manager->{'path_log'},  # stdout
-      $instance_manager->{'path_err'},  # stderr
-      '',                               # pid file path (not used)
-      { append_log_file => 1 }          # append log files
-      );
-
-  if ( ! $instance_manager->{'pid'} )
-  {
-    mtr_report('Could not start Instance Manager');
-    return;
-  }
-
-  # Instance Manager can be run in daemon mode. In this case, it creates
-  # several processes and the parent process, created by mtr_spawn(), exits just
-  # after start. So, we have to obtain Instance Manager PID from the PID file.
-
-  if ( ! sleep_until_file_created(
-                                  $instance_manager->{'path_pid'},
-                                  $instance_manager->{'start_timeout'},
-                                  -1)) # real PID is still unknown
-  {
-    mtr_report("Instance Manager PID file is missing");
-    return;
-  }
-
-  my $pid=  mtr_get_pid_from_file($instance_manager->{'path_pid'});
-  $instance_manager->{'pid'} = $pid;
-  mtr_verbose("im_start: pid: $pid");
-}
-
-
-sub im_stop($$) {
-  my $instance_manager = shift;
-  my $where = shift;
-
-  # Obtain mysqld-process pids before we start stopping IM (it can delete pid
-  # files).
-
-  my @mysqld_pids = ();
-  my $instances = $instance_manager->{'instances'};
-
-  push(@mysqld_pids, mtr_get_pid_from_file($instances->[0]->{'path_pid'}))
-    if -r $instances->[0]->{'path_pid'};
-
-  push(@mysqld_pids, mtr_get_pid_from_file($instances->[1]->{'path_pid'}))
-    if -r $instances->[1]->{'path_pid'};
-
-  # Re-read pid from the file, since during tests Instance Manager could have
-  # been restarted, so its pid could have been changed.
-
-  $instance_manager->{'pid'} =
-    mtr_get_pid_from_file($instance_manager->{'path_pid'})
-      if -f $instance_manager->{'path_pid'};
-
-  if (-f $instance_manager->{'path_angel_pid'})
-  {
-    $instance_manager->{'angel_pid'} =
-      mtr_get_pid_from_file($instance_manager->{'path_angel_pid'})
-  }
-  else
-  {
-    $instance_manager->{'angel_pid'} = undef;
-  }
-
-  # Inspired from mtr_stop_mysqld_servers().
-
-  start_reap_all();
-
-  # Try graceful shutdown.
-
-  mtr_verbose("Stopping IM-main, pid: $instance_manager->{'pid'}");
-  mtr_kill_process($instance_manager->{'pid'}, 'TERM', 10);
-
-  # If necessary, wait for angel process to die.
-
-  my $pid= $instance_manager->{'angel_pid'};
-  if (defined $pid)
-  {
-    mtr_verbose("Waiting for IM-angel to die, pid: $pid");
-
-    my $total_attempts= 10;
-
-    for (my $cur_attempt=1; $cur_attempt <= $total_attempts; ++$cur_attempt)
-    {
-      unless (kill (0, $pid))
-      {
-        mtr_verbose("IM-angel died.");
-        last;
-      }
-
-      sleep(1);
-    }
-  }
-
-  # Check if all processes shutdown cleanly
-  my $clean_shutdown= 0;
-
-  while (1)
-  {
-    # Check that IM-main died.
-
-    if (kill (0, $instance_manager->{'pid'}))
-    {
-      mtr_debug("IM-main is still alive.");
-      last;
-    }
-
-    # Check that IM-angel died.
-
-    if (defined $instance_manager->{'angel_pid'} &&
-        kill (0, $instance_manager->{'angel_pid'}))
-    {
-      mtr_debug("IM-angel is still alive.");
-      last;
-    }
-
-    # Check that all guarded mysqld-instances died.
-
-    my $guarded_mysqlds_dead= 1;
-
-    foreach my $pid (@mysqld_pids)
-    {
-      if (kill (0, $pid))
-      {
-        mtr_debug("Guarded mysqld ($pid) is still alive.");
-        $guarded_mysqlds_dead= 0;
-        last;
-      }
-    }
-
-    last unless $guarded_mysqlds_dead;
-
-    # Ok, all necessary processes are dead.
-
-    $clean_shutdown= 1;
-    last;
-  }
-
-  # Kill leftovers (the order is important).
-
-  if ($clean_shutdown)
-  {
-    mtr_debug("IM-shutdown was clean -- all processed died.");
-  }
-  else
-  {
-    mtr_debug("IM failed to shutdown gracefully. We have to clean the mess...");
-  }
-
-  unless ($clean_shutdown)
-  {
-
-    if (defined $instance_manager->{'angel_pid'})
-    {
-      mtr_verbose("Killing IM-angel, pid: $instance_manager->{'angel_pid'}");
-      mtr_kill_process($instance_manager->{'angel_pid'}, 'KILL', 10)
-    }
-
-    mtr_verbose("Killing IM-main, pid: $instance_manager->{'pid'}");
-    mtr_kill_process($instance_manager->{'pid'}, 'KILL', 10);
-
-    # Shutdown managed mysqld-processes. Some of them may be nonguarded, so IM
-    # will not stop them on shutdown. So, we should firstly try to end them
-    # legally.
-
-    mtr_verbose("Killing guarded mysqld(s) " . join(" ", @mysqld_pids));
-    mtr_kill_processes(\@mysqld_pids);
-
-    # Complain in error log so that a warning will be shown.
-    # 
-    # TODO: unless BUG#20761 is fixed, we will print the warning
-    # to stdout, so that it can be seen on console and does not
-    # produce pushbuild error.
-
-    # my $errlog= "$opt_vardir/log/mysql-test-run.pl.err";
-    # 
-    # open (ERRLOG, ">>$errlog") ||
-    #   mtr_error("Can not open error log ($errlog)");
-    # 
-    # my $ts= localtime();
-    # print ERRLOG
-    #   "Warning: [$ts] Instance Manager did not shutdown gracefully.\n";
-    # 
-    # close ERRLOG;
-
-    my $ts= localtime();
-    print "[$where] Warning: [$ts] Instance Manager did not shutdown gracefully.\n";
-  }
-
-  # That's all.
-
-  stop_reap_all();
-
-  $instance_manager->{'pid'} = undef;
-  $instance_manager->{'angel_pid'} = undef;
-}
-
 
 #
 # Run include/check-testcase.test

--- 1.38.3.1/innobase/btr/btr0btr.c	2006-08-30 15:25:38 +04:00
+++ 1.45/storage/innobase/btr/btr0btr.c	2006-08-30 15:25:38 +04:00
@@ -5,7 +5,7 @@ The B-tree
 
 Created 6/2/1994 Heikki Tuuri
 *******************************************************/
- 
+
 #include "btr0btr.h"
 
 #ifdef UNIV_NONINL
@@ -56,7 +56,7 @@ field. To the child page we can store no
 which are >= P in the alphabetical order, but < P1 if there is
 a next node pointer on the level, and P1 is its prefix.
 
-If a node pointer with a prefix P points to a non-leaf child, 
+If a node pointer with a prefix P points to a non-leaf child,
 then the leftmost record in the child must have the same
 prefix P. If it points to a leaf node, the child is not required
 to contain any record with a prefix equal to P. The leaf case
@@ -138,14 +138,14 @@ btr_root_get(
 	ulint	space;
 	ulint	root_page_no;
 	page_t*	root;
-	
+
 	space = dict_tree_get_space(tree);
 	root_page_no = dict_tree_get_page(tree);
 
 	root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr);
 	ut_a((ibool)!!page_is_comp(root) ==
-			UT_LIST_GET_FIRST(tree->tree_indexes)->table->comp);
-	
+			dict_table_is_comp(tree->tree_index->table));
+
 	return(root);
 }
 
@@ -175,21 +175,25 @@ btr_get_prev_user_rec(
 			return(prev_rec);
 		}
 	}
-	
+
 	page = buf_frame_align(rec);
 	prev_page_no = btr_page_get_prev(page, mtr);
 	space = buf_frame_get_space_id(page);
-	
+
 	if (prev_page_no != FIL_NULL) {
 
 		prev_page = buf_page_get_with_no_latch(space, prev_page_no,
 									mtr);
 		/* The caller must already have a latch to the brother */
 		ut_ad((mtr_memo_contains(mtr, buf_block_align(prev_page),
-		      				MTR_MEMO_PAGE_S_FIX))
-		      || (mtr_memo_contains(mtr, buf_block_align(prev_page),
-		      				MTR_MEMO_PAGE_X_FIX)));
+						MTR_MEMO_PAGE_S_FIX))
+			|| (mtr_memo_contains(mtr, buf_block_align(prev_page),
+					MTR_MEMO_PAGE_X_FIX)));
 		ut_a(page_is_comp(prev_page) == page_is_comp(page));
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_next(prev_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 
 		return(page_rec_get_prev(page_get_supremum_rec(prev_page)));
 	}
@@ -223,20 +227,24 @@ btr_get_next_user_rec(
 			return(next_rec);
 		}
 	}
-	
+
 	page = buf_frame_align(rec);
 	next_page_no = btr_page_get_next(page, mtr);
 	space = buf_frame_get_space_id(page);
-	
+
 	if (next_page_no != FIL_NULL) {
 
 		next_page = buf_page_get_with_no_latch(space, next_page_no,
 									mtr);
 		/* The caller must already have a latch to the brother */
 		ut_ad((mtr_memo_contains(mtr, buf_block_align(next_page),
-		      				MTR_MEMO_PAGE_S_FIX))
-		      || (mtr_memo_contains(mtr, buf_block_align(next_page),
-		      				MTR_MEMO_PAGE_X_FIX)));
+						MTR_MEMO_PAGE_S_FIX))
+			|| (mtr_memo_contains(mtr, buf_block_align(next_page),
+						MTR_MEMO_PAGE_X_FIX)));
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_prev(next_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 
 		ut_a(page_is_comp(next_page) == page_is_comp(page));
 		return(page_rec_get_next(page_get_infimum_rec(next_page)));
@@ -257,11 +265,11 @@ btr_page_create(
 	mtr_t*		mtr)	/* in: mtr */
 {
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	page_create(page, mtr,
-			UT_LIST_GET_FIRST(tree->tree_indexes)->table->comp);
+			dict_table_is_comp(tree->tree_index->table));
 	buf_block_align(page)->check_index_page_at_flush = TRUE;
-	
+
 	btr_page_set_index_id(page, tree->id, mtr);
 }
 
@@ -281,7 +289,7 @@ btr_page_alloc_for_ibuf(
 	page_t*		new_page;
 
 	root = btr_root_get(tree, mtr);
-	
+
 	node_addr = flst_get_first(root + PAGE_HEADER
 					+ PAGE_BTR_IBUF_FREE_LIST, mtr);
 	ut_a(node_addr.page != FIL_NULL);
@@ -293,7 +301,7 @@ btr_page_alloc_for_ibuf(
 #endif /* UNIV_SYNC_DEBUG */
 
 	flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
-		    new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE,
+		new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE,
 									mtr);
 	ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr));
 
@@ -328,7 +336,7 @@ btr_page_alloc(
 	}
 
 	root = btr_root_get(tree, mtr);
-		
+
 	if (level == 0) {
 		seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
 	} else {
@@ -338,7 +346,7 @@ btr_page_alloc(
 	/* Parameter TRUE below states that the caller has made the
 	reservation for free extents, and thus we know that a page can
 	be allocated: */
-	
+
 	new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no,
 						file_direction, TRUE, mtr);
 	if (new_page_no == FIL_NULL) {
@@ -351,9 +359,9 @@ btr_page_alloc(
 #ifdef UNIV_SYNC_DEBUG
 	buf_page_dbg_add_level(new_page, SYNC_TREE_NODE_NEW);
 #endif /* UNIV_SYNC_DEBUG */
-							
+
 	return(new_page);
-}	
+}
 
 /******************************************************************
 Gets the number of pages in a B-tree. */
@@ -376,20 +384,20 @@ btr_get_size(
 	mtr_s_lock(dict_tree_get_lock(index->tree), &mtr);
 
 	root = btr_root_get(index->tree, &mtr);
-		
+
 	if (flag == BTR_N_LEAF_PAGES) {
 		seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
-		
+
 		fseg_n_reserved_pages(seg_header, &n, &mtr);
-		
+
 	} else if (flag == BTR_TOTAL_SIZE) {
 		seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
 
 		n = fseg_n_reserved_pages(seg_header, &dummy, &mtr);
-		
+
 		seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
-		
-		n += fseg_n_reserved_pages(seg_header, &dummy, &mtr);		
+
+		n += fseg_n_reserved_pages(seg_header, &dummy, &mtr);
 	} else {
 		ut_error;
 	}
@@ -397,7 +405,7 @@ btr_get_size(
 	mtr_commit(&mtr);
 
 	return(n);
-}	
+}
 
 /******************************************************************
 Frees a page used in an ibuf tree. Puts the page to the free list of the
@@ -407,17 +415,17 @@ void
 btr_page_free_for_ibuf(
 /*===================*/
 	dict_tree_t*	tree,	/* in: index tree */
-	page_t*		page,	/* in: page to be freed, x-latched */	
+	page_t*		page,	/* in: page to be freed, x-latched */
 	mtr_t*		mtr)	/* in: mtr */
 {
 	page_t*		root;
 
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	root = btr_root_get(tree, mtr);
-	
+
 	flst_add_first(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
-		       page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
+		page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
 
 	ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
 									mtr));
@@ -432,7 +440,7 @@ void
 btr_page_free_low(
 /*==============*/
 	dict_tree_t*	tree,	/* in: index tree */
-	page_t*		page,	/* in: page to be freed, x-latched */	
+	page_t*		page,	/* in: page to be freed, x-latched */
 	ulint		level,	/* in: page level */
 	mtr_t*		mtr)	/* in: mtr */
 {
@@ -442,12 +450,12 @@ btr_page_free_low(
 	ulint		page_no;
 
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	/* The page gets invalid for optimistic searches: increment the frame
 	modify clock */
 
 	buf_frame_modify_clock_inc(page);
-	
+
 	if (tree->type & DICT_IBUF) {
 
 		btr_page_free_for_ibuf(tree, page, mtr);
@@ -456,7 +464,7 @@ btr_page_free_low(
 	}
 
 	root = btr_root_get(tree, mtr);
-	
+
 	if (level == 0) {
 		seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
 	} else {
@@ -465,9 +473,9 @@ btr_page_free_low(
 
 	space = buf_frame_get_space_id(page);
 	page_no = buf_frame_get_page_no(page);
-	
+
 	fseg_free_page(seg_header, space, page_no, mtr);
-}	
+}
 
 /******************************************************************
 Frees a file page used in an index tree. NOTE: cannot free field external
@@ -477,17 +485,17 @@ void
 btr_page_free(
 /*==========*/
 	dict_tree_t*	tree,	/* in: index tree */
-	page_t*		page,	/* in: page to be freed, x-latched */	
+	page_t*		page,	/* in: page to be freed, x-latched */
 	mtr_t*		mtr)	/* in: mtr */
 {
 	ulint		level;
 
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	level = btr_page_get_level(page, mtr);
-	
+
 	btr_page_free_low(tree, page, level, mtr);
-}	
+}
 
 /******************************************************************
 Sets the child node file address in a node pointer. */
@@ -507,12 +515,12 @@ btr_node_ptr_set_child_page_no(
 	ut_ad(0 < btr_page_get_level(buf_frame_align(rec), mtr));
 	ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec));
 
-	/* The child address is in the last field */	
+	/* The child address is in the last field */
 	field = rec_get_nth_field(rec, offsets,
 					rec_offs_n_fields(offsets) - 1, &len);
 
 	ut_ad(len == 4);
-	
+
 	mlog_write_ulint(field, page_no, MLOG_4BYTES, mtr);
 }
 
@@ -536,7 +544,7 @@ btr_node_ptr_get_child(
 	page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
 
 	page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
-	
+
 	return(page);
 }
 
@@ -567,14 +575,14 @@ btr_page_get_father_for_rec(
 	ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
 							MTR_MEMO_X_LOCK));
 	ut_a(page_rec_is_user_rec(user_rec));
-	
+
 	ut_ad(dict_tree_get_page(tree) != buf_frame_get_page_no(page));
 
 	heap = mem_heap_create(100);
 
 	tuple = dict_tree_build_node_ptr(tree, user_rec, 0, heap,
 					 btr_page_get_level(page, mtr));
-	index = UT_LIST_GET_FIRST(tree->tree_indexes);
+	index = tree->tree_index;
 
 	/* In the following, we choose just any index from the tree as the
 	first parameter for btr_cur_search_to_nth_level. */
@@ -589,7 +597,7 @@ btr_page_get_father_for_rec(
 						ULINT_UNDEFINED, &heap);
 
 	if (btr_node_ptr_get_child_page_no(node_ptr, offsets) !=
-                                                buf_frame_get_page_no(page)) {
+						buf_frame_get_page_no(page)) {
 		rec_t*	print_rec;
 		fputs("InnoDB: Dump of the child page:\n", stderr);
 		buf_page_print(buf_frame_align(page));
@@ -597,9 +605,9 @@ btr_page_get_father_for_rec(
 		buf_page_print(buf_frame_align(node_ptr));
 
 		fputs("InnoDB: Corruption of an index tree: table ", stderr);
-		ut_print_name(stderr, NULL, index->table_name);
+		ut_print_name(stderr, NULL, TRUE, index->table_name);
 		fputs(", index ", stderr);
-		ut_print_name(stderr, NULL, index->name);
+		ut_print_name(stderr, NULL, FALSE, index->name);
 		fprintf(stderr, ",\n"
 "InnoDB: father ptr page no %lu, child page no %lu\n",
 			(ulong)
@@ -677,13 +685,13 @@ btr_create(
 		buf_page_dbg_add_level(ibuf_hdr_frame, SYNC_TREE_NODE_NEW);
 #endif /* UNIV_SYNC_DEBUG */
 		ut_ad(buf_frame_get_page_no(ibuf_hdr_frame)
- 						== IBUF_HEADER_PAGE_NO);
+						== IBUF_HEADER_PAGE_NO);
 		/* Allocate then the next page to the segment: it will be the
- 		tree root page */
+		tree root page */
 
- 		page_no = fseg_alloc_free_page(
+		page_no = fseg_alloc_free_page(
 				ibuf_hdr_frame + IBUF_HEADER
- 				+ IBUF_TREE_SEG_HEADER, IBUF_TREE_ROOT_PAGE_NO,
+				+ IBUF_TREE_SEG_HEADER, IBUF_TREE_ROOT_PAGE_NO,
 				FSP_UP, mtr);
 		ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
 
@@ -692,14 +700,14 @@ btr_create(
 		frame = fseg_create(space, 0, PAGE_HEADER + PAGE_BTR_SEG_TOP,
 									mtr);
 	}
-	
+
 	if (frame == NULL) {
 
 		return(FIL_NULL);
 	}
 
 	page_no = buf_frame_get_page_no(frame);
-	
+
 #ifdef UNIV_SYNC_DEBUG
 	buf_page_dbg_add_level(frame, SYNC_TREE_NODE_NEW);
 #endif /* UNIV_SYNC_DEBUG */
@@ -708,9 +716,9 @@ btr_create(
 		/* It is an insert buffer tree: initialize the free list */
 
 		ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
-		
+
 		flst_init(frame + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr);
-	} else {	
+	} else {
 		/* It is a non-ibuf tree: create a file segment for leaf
 		pages */
 		fseg_create(space, page_no, PAGE_HEADER + PAGE_BTR_SEG_LEAF,
@@ -721,7 +729,7 @@ btr_create(
 		buf_page_dbg_add_level(frame, SYNC_TREE_NODE_NEW);
 #endif /* UNIV_SYNC_DEBUG */
 	}
-	
+
 	/* Create a new index page on the the allocated segment page */
 	page = page_create(frame, mtr, comp);
 	buf_block_align(page)->check_index_page_at_flush = TRUE;
@@ -731,7 +739,7 @@ btr_create(
 
 	/* Set the level of the new index page */
 	btr_page_set_level(page, 0, mtr);
-	
+
 	/* Set the next node and previous node fields */
 	btr_page_set_next(page, FIL_NULL, mtr);
 	btr_page_set_prev(page, FIL_NULL, mtr);
@@ -739,7 +747,7 @@ btr_create(
 	/* We reset the free bits for the page to allow creation of several
 	trees in the same mtr, otherwise the latch on a bitmap page would
 	prevent it because of the latching order */
-	
+
 	ibuf_reset_free_bits_with_type(type, page);
 
 	/* In the following assertion we test that two records of maximum
@@ -765,10 +773,10 @@ btr_free_but_not_root(
 	page_t*	root;
 	mtr_t	mtr;
 
-leaf_loop:	
+leaf_loop:
 	mtr_start(&mtr);
-	
-	root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr);	
+
+	root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr);
 
 	/* NOTE: page hash indexes are dropped when a page is freed inside
 	fsp0fsp. */
@@ -783,8 +791,8 @@ leaf_loop:	
 	}
 top_loop:
 	mtr_start(&mtr);
-	
-	root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr);	
+
+	root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr);
 
 	finished = fseg_free_step_not_header(
 				root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr);
@@ -793,7 +801,7 @@ top_loop:
 	if (!finished) {
 
 		goto top_loop;
-	}	
+	}
 }
 
 /****************************************************************
@@ -812,14 +820,14 @@ btr_free_root(
 
 	root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr);
 
-	btr_search_drop_page_hash_index(root);	
-top_loop:	
+	btr_search_drop_page_hash_index(root);
+top_loop:
 	finished = fseg_free_step(
 				root + PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr);
 	if (!finished) {
 
 		goto top_loop;
-	}	
+	}
 }
 
 /*****************************************************************
@@ -845,8 +853,8 @@ btr_page_reorganize_low(
 	ulint	max_ins_size2;
 
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
-	ut_ad(!!page_is_comp(page) == index->table->comp);
+							MTR_MEMO_PAGE_X_FIX));
+	ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
 	data_size1 = page_get_data_size(page);
 	max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1);
 
@@ -872,7 +880,7 @@ btr_page_reorganize_low(
 
 	page_create(page, mtr, page_is_comp(page));
 	buf_block_align(page)->check_index_page_at_flush = TRUE;
-	
+
 	/* Copy the records from the temporary space to the recreated page;
 	do not copy the lock bits yet */
 
@@ -880,7 +888,7 @@ btr_page_reorganize_low(
 				page_get_infimum_rec(new_page), index, mtr);
 	/* Copy max trx id to recreated page */
 	page_set_max_trx_id(page, page_get_max_trx_id(new_page));
-	
+
 	if (!recovery) {
 		/* Update the record lock bitmaps */
 		lock_move_reorganize_page(page, new_page);
@@ -892,7 +900,7 @@ btr_page_reorganize_low(
 	if (data_size1 != data_size2 || max_ins_size1 != max_ins_size2) {
 		buf_page_print(page);
 		buf_page_print(new_page);
-	        fprintf(stderr,
+		fprintf(stderr,
 "InnoDB: Error: page old data size %lu new data size %lu\n"
 "InnoDB: Error: page old max ins size %lu new max ins size %lu\n"
 "InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n",
@@ -955,7 +963,7 @@ btr_page_empty(
 	mtr_t*	mtr)	/* in: mtr */
 {
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	btr_search_drop_page_hash_index(page);
 
 	/* Recreate the page: note that global data on page (possible
@@ -990,10 +998,10 @@ btr_root_raise_and_insert(
 	rec_t*		rec;
 	mem_heap_t*	heap;
 	dtuple_t*	node_ptr;
-	ulint		level;	
+	ulint		level;
 	rec_t*		node_ptr_rec;
 	page_cur_t*	page_cursor;
-	
+
 	root = btr_cur_get_page(cursor);
 	tree = btr_cur_get_tree(cursor);
 
@@ -1001,24 +1009,24 @@ btr_root_raise_and_insert(
 	ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
 							MTR_MEMO_X_LOCK));
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(root),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	btr_search_drop_page_hash_index(root);
 
 	/* Allocate a new page to the tree. Root splitting is done by first
 	moving the root records to the new page, emptying the root, putting
 	a node pointer to the new page, and then splitting the new page. */
-	
+
 	new_page = btr_page_alloc(tree, 0, FSP_NO_DIR,
 				  btr_page_get_level(root, mtr), mtr);
 
 	btr_page_create(new_page, tree, mtr);
 
 	level = btr_page_get_level(root, mtr);
-	
+
 	/* Set the levels of the new index page and root page */
 	btr_page_set_level(new_page, level, mtr);
 	btr_page_set_level(root, level + 1, mtr);
-	
+
 	/* Set the next node and previous node fields of new page */
 	btr_page_set_next(new_page, FIL_NULL, mtr);
 	btr_page_set_prev(new_page, FIL_NULL, mtr);
@@ -1031,7 +1039,7 @@ btr_root_raise_and_insert(
 	perform a pessimistic update then we have stored the lock
 	information of the record to be inserted on the infimum of the
 	root page: we cannot discard the lock structs on the root page */
-	
+
 	lock_update_root_raise(new_page, root);
 
 	/* Create a memory heap where the node pointer is stored */
@@ -1039,17 +1047,17 @@ btr_root_raise_and_insert(
 
 	rec = page_rec_get_next(page_get_infimum_rec(new_page));
 	new_page_no = buf_frame_get_page_no(new_page);
-	
+
 	/* Build the node pointer (= node key and page address) for the
 	child */
 
 	node_ptr = dict_tree_build_node_ptr(tree, rec, new_page_no, heap,
-					                          level);
+								  level);
 	/* Reorganize the root to get free space */
 	btr_page_reorganize(root, cursor->index, mtr);
 
 	page_cursor = btr_cur_get_page_cur(cursor);
-	
+
 	/* Insert node pointer to the root */
 
 	page_cur_set_before_first(root, page_cursor);
@@ -1064,7 +1072,7 @@ btr_root_raise_and_insert(
 	node of a level: */
 
 	btr_set_min_rec_mark(node_ptr_rec, page_is_comp(root), mtr);
-		
+
 	/* Free the memory heap */
 	mem_heap_free(heap);
 
@@ -1073,15 +1081,14 @@ btr_root_raise_and_insert(
 /*	fprintf(stderr, "Root raise new page no %lu\n",
 					buf_frame_get_page_no(new_page)); */
 
-	ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes),
-								new_page);
+	ibuf_reset_free_bits(tree->tree_index, new_page);
 	/* Reposition the cursor to the child node */
 	page_cur_search(new_page, cursor->index, tuple,
 				PAGE_CUR_LE, page_cursor);
-	
+
 	/* Split the child and insert tuple */
 	return(btr_page_split_and_insert(cursor, tuple, mtr));
-}	
+}
 
 /*****************************************************************
 Decides if the page should be split at the convergence point of inserts
@@ -1105,22 +1112,22 @@ btr_page_get_split_rec_to_left(
 	insert_point = btr_cur_get_rec(cursor);
 
 	if (page_header_get_ptr(page, PAGE_LAST_INSERT)
-	    == page_rec_get_next(insert_point)) {
+		== page_rec_get_next(insert_point)) {
+
+		infimum = page_get_infimum_rec(page);
 
-	     	infimum = page_get_infimum_rec(page);
-		
 		/* If the convergence is in the middle of a page, include also
 		the record immediately before the new insert to the upper
 		page. Otherwise, we could repeatedly move from page to page
 		lots of records smaller than the convergence point. */
 
 		if (infimum != insert_point
-		    && page_rec_get_next(infimum) != insert_point) {
+			&& page_rec_get_next(infimum) != insert_point) {
 
 			*split_rec = insert_point;
 		} else {
-	     		*split_rec = page_rec_get_next(insert_point);
-	     	}
+			*split_rec = page_rec_get_next(insert_point);
+		}
 
 		return(TRUE);
 	}
@@ -1162,7 +1169,7 @@ btr_page_get_split_rec_to_right(
 		if (page_rec_is_supremum(next_rec)) {
 split_at_new:
 			/* Split at the new record to insert */
-	     		*split_rec = NULL;
+			*split_rec = NULL;
 		} else {
 			rec_t*	next_next_rec = page_rec_get_next(next_rec);
 			if (page_rec_is_supremum(next_next_rec)) {
@@ -1176,7 +1183,7 @@ split_at_new:
 			index, as they can do the necessary checks of the right
 			search position just by looking at the records on this
 			page. */
-		
+
 			*split_rec = next_next_rec;
 		}
 
@@ -1199,7 +1206,7 @@ btr_page_get_sure_split_rec(
 					upper half-page */
 	btr_cur_t*	cursor,		/* in: cursor at which insert
 					should be made */
-	dtuple_t*	tuple)		/* in: tuple to insert */	
+	dtuple_t*	tuple)		/* in: tuple to insert */
 {
 	page_t*	page;
 	ulint	insert_size;
@@ -1216,7 +1223,7 @@ btr_page_get_sure_split_rec(
 	ulint*	offsets;
 
 	page = btr_cur_get_page(cursor);
-	
+
 	insert_size = rec_get_converted_size(cursor->index, tuple);
 	free_space  = page_get_free_space_of_empty(page_is_comp(page));
 
@@ -1263,15 +1270,15 @@ btr_page_get_sure_split_rec(
 		}
 
 		n++;
-		
+
 		if (incl_data + page_dir_calc_reserved_space(n)
-                    >= total_space / 2) {
+			>= total_space / 2) {
 
-                    	if (incl_data + page_dir_calc_reserved_space(n)
-                    	    <= free_space) {
-                    	    	/* The next record will be the first on
-                    	    	the right half page if it is not the
-                    	    	supremum record of page */
+			if (incl_data + page_dir_calc_reserved_space(n)
+				<= free_space) {
+				/* The next record will be the first on
+				the right half page if it is not the
+				supremum record of page */
 
 				if (rec == ins_rec) {
 					rec = NULL;
@@ -1286,7 +1293,7 @@ btr_page_get_sure_split_rec(
 				if (!page_rec_is_supremum(next_rec)) {
 					rec = next_rec;
 				}
-                    	}
+			}
 
 func_exit:
 			if (UNIV_LIKELY_NULL(heap)) {
@@ -1295,7 +1302,7 @@ func_exit:
 			return(rec);
 		}
 	}
-}		
+}
 
 /*****************************************************************
 Returns TRUE if the insert fits on the appropriate half-page with the
@@ -1323,7 +1330,7 @@ btr_page_insert_fits(
 	rec_t*	rec;
 	rec_t*	end_rec;
 	ulint*	offs;
-	
+
 	page = btr_cur_get_page(cursor);
 
 	ut_ad(!split_rec == !offsets);
@@ -1339,11 +1346,11 @@ btr_page_insert_fits(
 
 	total_data   = page_get_data_size(page) + insert_size;
 	total_n_recs = page_get_n_recs(page) + 1;
-	
+
 	/* We determine which records (from rec to end_rec, not including
 	end_rec) will end up on the other half page from tuple when it is
 	inserted. */
-	
+
 	if (split_rec == NULL) {
 		rec = page_rec_get_next(page_get_infimum_rec(page));
 		end_rec = page_rec_get_next(btr_cur_get_rec(cursor));
@@ -1351,14 +1358,14 @@ btr_page_insert_fits(
 	} else if (cmp_dtuple_rec(tuple, split_rec, offsets) >= 0) {
 
 		rec = page_rec_get_next(page_get_infimum_rec(page));
- 		end_rec = split_rec;
+		end_rec = split_rec;
 	} else {
 		rec = split_rec;
 		end_rec = page_get_supremum_rec(page);
 	}
 
 	if (total_data + page_dir_calc_reserved_space(total_n_recs)
-	    <= free_space) {
+		<= free_space) {
 
 		/* Ok, there will be enough available space on the
 		half page where the tuple is inserted */
@@ -1379,7 +1386,7 @@ btr_page_insert_fits(
 		total_n_recs--;
 
 		if (total_data + page_dir_calc_reserved_space(total_n_recs)
-                    <= free_space) {
+			<= free_space) {
 
 			/* Ok, there will be enough available space on the
 			half page where the tuple is inserted */
@@ -1391,7 +1398,7 @@ btr_page_insert_fits(
 	}
 
 	return(FALSE);
-}		
+}
 
 /***********************************************************
 Inserts a data tuple to a tree on a non-leaf level. It is assumed
@@ -1406,25 +1413,22 @@ btr_insert_on_non_leaf_level(
 	mtr_t*		mtr)	/* in: mtr */
 {
 	big_rec_t*	dummy_big_rec;
-	btr_cur_t	cursor;		
+	btr_cur_t	cursor;
 	ulint		err;
 	rec_t*		rec;
 
 	ut_ad(level > 0);
-	
+
 	/* In the following, choose just any index from the tree as the
 	first parameter for btr_cur_search_to_nth_level. */
 
-	btr_cur_search_to_nth_level(UT_LIST_GET_FIRST(tree->tree_indexes),
-				    level, tuple, PAGE_CUR_LE,
-				    BTR_CONT_MODIFY_TREE,
-				    &cursor, 0, mtr);
+	btr_cur_search_to_nth_level(tree->tree_index,
+		level, tuple, PAGE_CUR_LE, BTR_CONT_MODIFY_TREE,
+		&cursor, 0, mtr);
 
 	err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
-					| BTR_KEEP_SYS_FLAG
-					| BTR_NO_UNDO_LOG_FLAG,
-					&cursor, tuple,
-					&rec, &dummy_big_rec, NULL, mtr);
+		| BTR_KEEP_SYS_FLAG | BTR_NO_UNDO_LOG_FLAG,
+		&cursor, tuple, &rec, &dummy_big_rec, NULL, mtr);
 	ut_a(err == DB_SUCCESS);
 }
 
@@ -1455,12 +1459,12 @@ btr_attach_half_pages(
 	ulint		lower_page_no;
 	ulint		upper_page_no;
 	dtuple_t*	node_ptr_upper;
-	mem_heap_t* 	heap;
+	mem_heap_t*	heap;
 
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(new_page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	ut_a(page_is_comp(page) == page_is_comp(new_page));
 
 	/* Create a memory heap where the data tuple is stored */
@@ -1477,12 +1481,12 @@ btr_attach_half_pages(
 		/* Look from the tree for the node pointer to page */
 		node_ptr = btr_page_get_father_node_ptr(tree, page, mtr);
 
-		/* Replace the address of the old child node (= page) with the 
+		/* Replace the address of the old child node (= page) with the
 		address of the new lower half */
 
 		btr_node_ptr_set_child_page_no(node_ptr,
 			rec_get_offsets(node_ptr,
-					UT_LIST_GET_FIRST(tree->tree_indexes),
+					tree->tree_index,
 					NULL, ULINT_UNDEFINED, &heap),
 			lower_page_no, mtr);
 		mem_heap_empty(heap);
@@ -1492,7 +1496,7 @@ btr_attach_half_pages(
 		lower_page = page;
 		upper_page = new_page;
 	}
-				   
+
 	/* Get the level of the split pages */
 	level = btr_page_get_level(page, mtr);
 
@@ -1500,13 +1504,13 @@ btr_attach_half_pages(
 	half */
 
 	node_ptr_upper = dict_tree_build_node_ptr(tree, split_rec,
-					     upper_page_no, heap, level);
+		upper_page_no, heap, level);
 
 	/* Insert it next to the pointer to the lower half. Note that this
 	may generate recursion leading to a split on the higher level. */
 
 	btr_insert_on_non_leaf_level(tree, level + 1, node_ptr_upper, mtr);
-		
+
 	/* Free the memory heap */
 	mem_heap_free(heap);
 
@@ -1515,13 +1519,17 @@ btr_attach_half_pages(
 	prev_page_no = btr_page_get_prev(page, mtr);
 	next_page_no = btr_page_get_next(page, mtr);
 	space = buf_frame_get_space_id(page);
-	
+
 	/* Update page links of the level */
-	
+
 	if (prev_page_no != FIL_NULL) {
 
 		prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr);
 		ut_a(page_is_comp(prev_page) == page_is_comp(page));
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_next(prev_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 
 		btr_page_set_next(prev_page, lower_page_no, mtr);
 	}
@@ -1533,7 +1541,7 @@ btr_attach_half_pages(
 
 		btr_page_set_prev(next_page, upper_page_no, mtr);
 	}
-	
+
 	btr_page_set_prev(lower_page, prev_page_no, mtr);
 	btr_page_set_next(lower_page, upper_page_no, mtr);
 	btr_page_set_level(lower_page, level, mtr);
@@ -1590,7 +1598,7 @@ func_start:
 	mem_heap_empty(heap);
 	offsets = NULL;
 	tree = btr_cur_get_tree(cursor);
-	
+
 	ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
 							MTR_MEMO_X_LOCK));
 #ifdef UNIV_SYNC_DEBUG
@@ -1600,9 +1608,9 @@ func_start:
 	page = btr_cur_get_page(cursor);
 
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	ut_ad(page_get_n_recs(page) >= 2);
-	
+
 	page_no = buf_frame_get_page_no(page);
 
 	/* 1. Decide the split record; split_rec == NULL means that the
@@ -1613,7 +1621,7 @@ func_start:
 		direction = FSP_UP;
 		hint_page_no = page_no + 1;
 		split_rec = btr_page_get_sure_split_rec(cursor, tuple);
-		
+
 	} else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) {
 		direction = FSP_UP;
 		hint_page_no = page_no + 1;
@@ -1631,7 +1639,7 @@ func_start:
 	new_page = btr_page_alloc(tree, hint_page_no, direction,
 					btr_page_get_level(page, mtr), mtr);
 	btr_page_create(new_page, tree, mtr);
-	
+
 	/* 3. Calculate the first record on the upper half-page, and the
 	first record (move_limit) on original page which ends up on the
 	upper half */
@@ -1646,7 +1654,7 @@ func_start:
 							cursor->index, tuple);
 		move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
 	}
-	
+
 	/* 4. Do first the modifications in the tree structure */
 
 	btr_attach_half_pages(tree, page, first_rec, new_page, direction, mtr);
@@ -1670,7 +1678,7 @@ func_start:
 		insert_will_fit = btr_page_insert_fits(cursor,
 					NULL, NULL, tuple, heap);
 	}
-	
+
 	if (insert_will_fit && (btr_page_get_level(page, mtr) == 0)) {
 
 		mtr_memo_release(mtr, dict_tree_get_lock(tree),
@@ -1737,7 +1745,7 @@ func_start:
 		mem_heap_free(heap);
 		return(rec);
 	}
-	
+
 	/* 8. If insert did not fit, try page reorganization */
 
 	btr_page_reorganize(insert_page, cursor->index, mtr);
@@ -1749,7 +1757,7 @@ func_start:
 	if (rec == NULL) {
 		/* The insert did not fit on the page: loop back to the
 		start of the function for a new split */
-		
+
 		/* We play safe and reset the free bits for new_page */
 		ibuf_reset_free_bits(cursor->index, new_page);
 
@@ -1771,8 +1779,8 @@ func_start:
 				buf_frame_get_page_no(left_page),
 				buf_frame_get_page_no(right_page)); */
 
-	ut_ad(page_validate(left_page, UT_LIST_GET_FIRST(tree->tree_indexes)));
-	ut_ad(page_validate(right_page, UT_LIST_GET_FIRST(tree->tree_indexes)));
+	ut_ad(page_validate(left_page, tree->tree_index));
+	ut_ad(page_validate(right_page, tree->tree_index));
 
 	mem_heap_free(heap);
 	return(rec);
@@ -1787,28 +1795,32 @@ btr_level_list_remove(
 	dict_tree_t*	tree __attribute__((unused)), /* in: index tree */
 	page_t*		page,	/* in: page to remove */
 	mtr_t*		mtr)	/* in: mtr */
-{	
+{
 	ulint	space;
 	ulint	prev_page_no;
 	page_t*	prev_page;
 	ulint	next_page_no;
 	page_t*	next_page;
-	
+
 	ut_ad(tree && page && mtr);
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	/* Get the previous and next page numbers of page */
 
 	prev_page_no = btr_page_get_prev(page, mtr);
 	next_page_no = btr_page_get_next(page, mtr);
 	space = buf_frame_get_space_id(page);
-	
+
 	/* Update page links of the level */
-	
+
 	if (prev_page_no != FIL_NULL) {
 
 		prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr);
 		ut_a(page_is_comp(prev_page) == page_is_comp(page));
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_next(prev_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 
 		btr_page_set_next(prev_page, next_page_no, mtr);
 	}
@@ -1817,11 +1829,15 @@ btr_level_list_remove(
 
 		next_page = btr_page_get(space, next_page_no, RW_X_LATCH, mtr);
 		ut_a(page_is_comp(next_page) == page_is_comp(page));
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_prev(next_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 
 		btr_page_set_prev(next_page, prev_page_no, mtr);
 	}
 }
-	
+
 /********************************************************************
 Writes the redo log record for setting an index record as the predefined
 minimum record. */
@@ -1906,15 +1922,14 @@ btr_node_ptr_delete(
 	btr_cur_t	cursor;
 	ibool		compressed;
 	ulint		err;
-	
+
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 							MTR_MEMO_PAGE_X_FIX));
 	/* Delete node pointer on father page */
 
 	node_ptr = btr_page_get_father_node_ptr(tree, page, mtr);
 
-	btr_cur_position(UT_LIST_GET_FIRST(tree->tree_indexes), node_ptr,
-								&cursor);
+	btr_cur_position(tree->tree_index, node_ptr, &cursor);
 	compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, FALSE,
 									mtr);
 	ut_a(err == DB_SUCCESS);
@@ -1945,33 +1960,33 @@ btr_lift_page_up(
 	ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
 	ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
-			      				MTR_MEMO_PAGE_X_FIX));
+							MTR_MEMO_PAGE_X_FIX));
 	father_page = buf_frame_align(
 			btr_page_get_father_node_ptr(tree, page, mtr));
-	
+
 	page_level = btr_page_get_level(page, mtr);
-	index = UT_LIST_GET_FIRST(tree->tree_indexes);
+	index = tree->tree_index;
 
 	btr_search_drop_page_hash_index(page);
-	
+
 	/* Make the father empty */
 	btr_page_empty(father_page, mtr);
 
 	/* Move records to the father */
- 	page_copy_rec_list_end(father_page, page, page_get_infimum_rec(page),
+	page_copy_rec_list_end(father_page, page, page_get_infimum_rec(page),
 								index, mtr);
 	lock_update_copy_and_discard(father_page, page);
 
 	btr_page_set_level(father_page, page_level, mtr);
 
 	/* Free the file page */
-	btr_page_free(tree, page, mtr);		
+	btr_page_free(tree, page, mtr);
 
 	/* We play safe and reset the free bits for the father */
 	ibuf_reset_free_bits(index, father_page);
 	ut_ad(page_validate(father_page, index));
 	ut_ad(btr_check_node_ptr(tree, father_page, mtr));
-}	
+}
 
 /*****************************************************************
 Tries to merge the page first to the left immediate brother if such a
@@ -2014,7 +2029,7 @@ btr_compress(
 	page = btr_cur_get_page(cursor);
 	tree = btr_cur_get_tree(cursor);
 	comp = page_is_comp(page);
-	ut_a((ibool)!!comp == cursor->index->table->comp);
+	ut_a((ibool)!!comp == dict_table_is_comp(cursor->index->table));
 
 	ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
 							MTR_MEMO_X_LOCK));
@@ -2037,16 +2052,24 @@ btr_compress(
 	/* Decide the page to which we try to merge and which will inherit
 	the locks */
 
-	if (left_page_no != FIL_NULL) {
+	is_left = left_page_no != FIL_NULL;
+
+	if (is_left) {
 
-		is_left = TRUE;
 		merge_page = btr_page_get(space, left_page_no, RW_X_LATCH,
 									mtr);
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_next(merge_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 	} else if (right_page_no != FIL_NULL) {
 
-		is_left = FALSE;
 		merge_page = btr_page_get(space, right_page_no, RW_X_LATCH,
 									mtr);
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_prev(merge_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 	} else {
 		/* The page is the only one on the level, lift the records
 		to the father */
@@ -2054,7 +2077,7 @@ btr_compress(
 
 		return;
 	}
-	
+
 	n_recs = page_get_n_recs(page);
 	data_size = page_get_data_size(page);
 	ut_a(page_is_comp(merge_page) == comp);
@@ -2071,7 +2094,7 @@ btr_compress(
 	ut_ad(page_validate(merge_page, cursor->index));
 
 	max_ins_size = page_get_max_insert_size(merge_page, n_recs);
-	
+
 	if (data_size > max_ins_size) {
 
 		/* We have to reorganize merge_page */
@@ -2103,7 +2126,7 @@ btr_compress(
 		mem_heap_t*	heap		= NULL;
 		ulint		offsets_[REC_OFFS_NORMAL_SIZE];
 		*offsets_ = (sizeof offsets_) / sizeof *offsets_;
-		/* Replace the address of the old child node (= page) with the 
+		/* Replace the address of the old child node (= page) with the
 		address of the merge page to the right */
 
 		btr_node_ptr_set_child_page_no(node_ptr,
@@ -2115,7 +2138,7 @@ btr_compress(
 		}
 		btr_node_ptr_delete(tree, merge_page, mtr);
 	}
-	
+
 	/* Move records to the merge page */
 	if (is_left) {
 		orig_pred = page_rec_get_prev(
@@ -2136,14 +2159,14 @@ btr_compress(
 	/* We have added new records to merge_page: update its free bits */
 	ibuf_update_free_bits_if_full(cursor->index, merge_page,
 					UNIV_PAGE_SIZE, ULINT_UNDEFINED);
-					
+
 	ut_ad(page_validate(merge_page, cursor->index));
 
 	/* Free the file page */
-	btr_page_free(tree, page, mtr);		
+	btr_page_free(tree, page, mtr);
 
 	ut_ad(btr_check_node_ptr(tree, merge_page, mtr));
-}	
+}
 
 /*****************************************************************
 Discards a page that is the only page on its level. */
@@ -2158,7 +2181,7 @@ btr_discard_only_page_on_level(
 	rec_t*	node_ptr;
 	page_t*	father_page;
 	ulint	page_level;
-	
+
 	ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
 	ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
@@ -2175,7 +2198,7 @@ btr_discard_only_page_on_level(
 	btr_page_set_level(father_page, page_level, mtr);
 
 	/* Free the file page */
-	btr_page_free(tree, page, mtr);		
+	btr_page_free(tree, page, mtr);
 
 	if (buf_frame_get_page_no(father_page) == dict_tree_get_page(tree)) {
 		/* The father is the root page */
@@ -2183,14 +2206,13 @@ btr_discard_only_page_on_level(
 		btr_page_empty(father_page, mtr);
 
 		/* We play safe and reset the free bits for the father */
-		ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes),
-								father_page);
+		ibuf_reset_free_bits(tree->tree_index, father_page);
 	} else {
 		ut_ad(page_get_n_recs(father_page) == 1);
 
 		btr_discard_only_page_on_level(tree, father_page, mtr);
 	}
-}	
+}
 
 /*****************************************************************
 Discards a page from a B-tree. This is used to remove the last record from
@@ -2209,10 +2231,9 @@ btr_discard_page(
 	ulint		left_page_no;
 	ulint		right_page_no;
 	page_t*		merge_page;
-	ibool		is_left;
 	page_t*		page;
 	rec_t*		node_ptr;
-	
+
 	page = btr_cur_get_page(cursor);
 	tree = btr_cur_get_tree(cursor);
 
@@ -2222,20 +2243,26 @@ btr_discard_page(
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 							MTR_MEMO_PAGE_X_FIX));
 	space = dict_tree_get_space(tree);
-	
+
 	/* Decide the page which will inherit the locks */
 
 	left_page_no = btr_page_get_prev(page, mtr);
 	right_page_no = btr_page_get_next(page, mtr);
 
 	if (left_page_no != FIL_NULL) {
-		is_left = TRUE;
 		merge_page = btr_page_get(space, left_page_no, RW_X_LATCH,
 									mtr);
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_next(merge_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 	} else if (right_page_no != FIL_NULL) {
-		is_left = FALSE;
 		merge_page = btr_page_get(space, right_page_no, RW_X_LATCH,
 									mtr);
+#ifdef UNIV_BTR_DEBUG
+		ut_a(btr_page_get_prev(merge_page, mtr)
+				== buf_frame_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
 	} else {
 		btr_discard_only_page_on_level(tree, page, mtr);
 
@@ -2244,7 +2271,7 @@ btr_discard_page(
 
 	ut_a(page_is_comp(merge_page) == page_is_comp(page));
 	btr_search_drop_page_hash_index(page);
-	
+
 	if (left_page_no == FIL_NULL && btr_page_get_level(page, mtr) > 0) {
 
 		/* We have to mark the leftmost node pointer on the right
@@ -2255,25 +2282,25 @@ btr_discard_page(
 		ut_ad(page_rec_is_user_rec(node_ptr));
 
 		btr_set_min_rec_mark(node_ptr, page_is_comp(merge_page), mtr);
-	}	
-	
+	}
+
 	btr_node_ptr_delete(tree, page, mtr);
 
 	/* Remove the page from the level list */
 	btr_level_list_remove(tree, page, mtr);
 
-	if (is_left) {
+	if (left_page_no != FIL_NULL) {
 		lock_update_discard(page_get_supremum_rec(merge_page), page);
 	} else {
 		lock_update_discard(page_rec_get_next(
-				    page_get_infimum_rec(merge_page)), page);
+				page_get_infimum_rec(merge_page)), page);
 	}
 
 	/* Free the file page */
-	btr_page_free(tree, page, mtr);		
+	btr_page_free(tree, page, mtr);
 
 	ut_ad(btr_check_node_ptr(tree, merge_page, mtr));
-}	
+}
 
 #ifdef UNIV_BTR_PRINT
 /*****************************************************************
@@ -2297,7 +2324,7 @@ btr_print_size(
 	}
 
 	mtr_start(&mtr);
-	
+
 	root = btr_root_get(tree, &mtr);
 
 	seg = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
@@ -2313,7 +2340,7 @@ btr_print_size(
 		fseg_print(seg, &mtr);
 	}
 
-	mtr_commit(&mtr); 	
+	mtr_commit(&mtr);
 }
 
 /****************************************************************
@@ -2341,14 +2368,14 @@ btr_print_recursive(
 	ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 							MTR_MEMO_PAGE_X_FIX));
 	fprintf(stderr, "NODE ON LEVEL %lu page number %lu\n",
-	       (ulong) btr_page_get_level(page, mtr),
-	       (ulong) buf_frame_get_page_no(page));
-	
+		(ulong) btr_page_get_level(page, mtr),
+		(ulong) buf_frame_get_page_no(page));
+
 	index = UT_LIST_GET_FIRST(tree->tree_indexes);
 	page_print(page, index, width, width);
-	
+
 	n_recs = page_get_n_recs(page);
-	
+
 	page_cur_set_before_first(page, &cursor);
 	page_cur_move_to_next(&cursor);
 
@@ -2413,6 +2440,7 @@ btr_print_tree(
 }
 #endif /* UNIV_BTR_PRINT */
 
+#ifdef UNIV_DEBUG
 /****************************************************************
 Checks that the node pointer to a page is appropriate. */
 
@@ -2436,28 +2464,29 @@ btr_check_node_ptr(
 	}
 
 	node_ptr = btr_page_get_father_node_ptr(tree, page, mtr);
- 
+
 	if (btr_page_get_level(page, mtr) == 0) {
 
 		return(TRUE);
 	}
-	
+
 	heap = mem_heap_create(256);
-		
+
 	node_ptr_tuple = dict_tree_build_node_ptr(
 				tree,
 				page_rec_get_next(page_get_infimum_rec(page)),
 				0, heap, btr_page_get_level(page, mtr));
-				
+
 	ut_a(cmp_dtuple_rec(node_ptr_tuple, node_ptr,
 			rec_get_offsets(node_ptr,
-			dict_tree_find_index(tree, node_ptr),
+			tree->tree_index,
 			NULL, ULINT_UNDEFINED, &heap)) == 0);
 
 	mem_heap_free(heap);
 
 	return(TRUE);
 }
+#endif /* UNIV_DEBUG */
 
 /****************************************************************
 Display identification information for a record. */
@@ -2481,7 +2510,7 @@ the index. */
 
 ibool
 btr_index_rec_validate(
-/*====================*/
+/*===================*/
 					/* out: TRUE if ok */
 	rec_t*		rec,		/* in: index record */
 	dict_index_t*	index,		/* in: index */
@@ -2501,18 +2530,20 @@ btr_index_rec_validate(
 	page = buf_frame_align(rec);
 
 	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
-	        /* The insert buffer index tree can contain records from any
-	        other index: we cannot check the number of fields or
-	        their length */
+		/* The insert buffer index tree can contain records from any
+		other index: we cannot check the number of fields or
+		their length */
 
-	        return(TRUE);
+		return(TRUE);
 	}
 
-	if (UNIV_UNLIKELY((ibool)!!page_is_comp(page) != index->table->comp)) {
+	if (UNIV_UNLIKELY((ibool)!!page_is_comp(page)
+			!= dict_table_is_comp(index->table))) {
 		btr_index_rec_validate_report(page, rec, index);
 		fprintf(stderr, "InnoDB: compact flag=%lu, should be %lu\n",
 			(ulong) !!page_is_comp(page),
-			(ulong) index->table->comp);
+			(ulong) dict_table_is_comp(index->table));
+
 		return(FALSE);
 	}
 
@@ -2546,12 +2577,12 @@ btr_index_rec_validate(
 		their type is CHAR. */
 
 		if ((dict_index_get_nth_field(index, i)->prefix_len == 0
-		    && len != UNIV_SQL_NULL && fixed_size
-		    && len != fixed_size)
+				&& len != UNIV_SQL_NULL && fixed_size
+				&& len != fixed_size)
 		   ||
 		   (dict_index_get_nth_field(index, i)->prefix_len > 0
-		    && len != UNIV_SQL_NULL
-		    && len >
+			   && len != UNIV_SQL_NULL
+			   && len >
 			   dict_index_get_nth_field(index, i)->prefix_len)) {
 
 			btr_index_rec_validate_report(page, rec, index);
@@ -2576,7 +2607,7 @@ btr_index_rec_validate(
 	if (UNIV_LIKELY_NULL(heap)) {
 		mem_heap_free(heap);
 	}
-	return(TRUE);			
+	return(TRUE);
 }
 
 /****************************************************************
@@ -2590,9 +2621,9 @@ btr_index_page_validate(
 	page_t*		page,	/* in: index page */
 	dict_index_t*	index)	/* in: index */
 {
-	page_cur_t 	cur;
+	page_cur_t	cur;
 	ibool		ret	= TRUE;
-	
+
 	page_cur_set_before_first(page, &cur);
 	page_cur_move_to_next(&cur);
 
@@ -2610,7 +2641,7 @@ btr_index_page_validate(
 		page_cur_move_to_next(&cur);
 	}
 
-	return(ret);	
+	return(ret);
 }
 
 /****************************************************************
@@ -2686,12 +2717,12 @@ btr_validate_level(
 	mtr_start(&mtr);
 
 	mtr_x_lock(dict_tree_get_lock(tree), &mtr);
-	
+
 	page = btr_root_get(tree, &mtr);
 
 	space = buf_frame_get_space_id(page);
 
-	index = UT_LIST_GET_FIRST(tree->tree_indexes);
+	index = tree->tree_index;
 
 	while (level != btr_page_get_level(page, &mtr)) {
 
@@ -2733,21 +2764,43 @@ loop:
 			ret = FALSE;
 		}
 	}
-	
+
 	ut_a(btr_page_get_level(page, &mtr) == level);
 
 	right_page_no = btr_page_get_next(page, &mtr);
 	left_page_no = btr_page_get_prev(page, &mtr);
 
 	ut_a((page_get_n_recs(page) > 0)
-	     || ((level == 0) &&
+		|| ((level == 0) &&
 		  (buf_frame_get_page_no(page) == dict_tree_get_page(tree))));
 
 	if (right_page_no != FIL_NULL) {
 		rec_t*	right_rec;
 		right_page = btr_page_get(space, right_page_no, RW_X_LATCH,
 									&mtr);
-		ut_a(page_is_comp(right_page) == page_is_comp(page));
+		if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr)
+				!= buf_frame_get_page_no(page))) {
+			btr_validate_report2(index, level, page, right_page);
+			fputs("InnoDB: broken FIL_PAGE_NEXT"
+				" or FIL_PAGE_PREV links\n", stderr);
+			buf_page_print(page);
+			buf_page_print(right_page);
+
+			ret = FALSE;
+		}
+
+		if (UNIV_UNLIKELY(page_is_comp(right_page)
+				!= page_is_comp(page))) {
+			btr_validate_report2(index, level, page, right_page);
+			fputs("InnoDB: 'compact' flag mismatch\n", stderr);
+			buf_page_print(page);
+			buf_page_print(right_page);
+
+			ret = FALSE;
+
+			goto node_ptr_fails;
+		}
+
 		rec = page_rec_get_prev(page_get_supremum_rec(page));
 		right_rec = page_rec_get_next(
 					page_get_infimum_rec(right_page));
@@ -2755,8 +2808,8 @@ loop:
 					offsets, ULINT_UNDEFINED, &heap);
 		offsets2 = rec_get_offsets(right_rec, index,
 					offsets2, ULINT_UNDEFINED, &heap);
-		if (cmp_rec_rec(rec, right_rec, offsets, offsets2, index)
-				>= 0) {
+		if (UNIV_UNLIKELY(cmp_rec_rec(rec, right_rec,
+				offsets, offsets2, index) >= 0)) {
 
 			btr_validate_report2(index, level, page, right_page);
 
@@ -2776,10 +2829,10 @@ loop:
 			rec_print(stderr, rec, index);
 			putc('\n', stderr);
 
-	  		ret = FALSE;
-	  	}
+			ret = FALSE;
+		}
 	}
-	
+
 	if (level > 0 && left_page_no == FIL_NULL) {
 		ut_a(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
 			page_rec_get_next(page_get_infimum_rec(page)),
@@ -2789,7 +2842,7 @@ loop:
 	if (buf_frame_get_page_no(page) != dict_tree_get_page(tree)) {
 
 		/* Check father node pointers */
-	
+
 		node_ptr = btr_page_get_father_node_ptr(tree, page, &mtr);
 		father_page = buf_frame_align(node_ptr);
 		offsets	= rec_get_offsets(node_ptr, index,
@@ -2822,25 +2875,25 @@ loop:
 				&mtr);
 			rec_print(stderr, rec, index);
 			putc('\n', stderr);
-		   	ret = FALSE;
+			ret = FALSE;
 
-		   	goto node_ptr_fails;
+			goto node_ptr_fails;
 		}
 
 		if (btr_page_get_level(page, &mtr) > 0) {
 			offsets	= rec_get_offsets(node_ptr, index,
 					offsets, ULINT_UNDEFINED, &heap);
-		
+
 			node_ptr_tuple = dict_tree_build_node_ptr(
 					tree,
 					page_rec_get_next(
 						page_get_infimum_rec(page)),
 						0, heap,
-       					btr_page_get_level(page, &mtr));
+					btr_page_get_level(page, &mtr));
 
 			if (cmp_dtuple_rec(node_ptr_tuple, node_ptr,
 								offsets)) {
-			  	rec_t*	first_rec	= page_rec_get_next(
+				rec_t*	first_rec	= page_rec_get_next(
 					page_get_infimum_rec(page));
 
 				btr_validate_report1(index, level, page);
@@ -2855,9 +2908,9 @@ loop:
 				fputs("InnoDB: first rec ", stderr);
 				rec_print(stderr, first_rec, index);
 				putc('\n', stderr);
-		   		ret = FALSE;
+				ret = FALSE;
 
-		   		goto node_ptr_fails;
+				goto node_ptr_fails;
 			}
 		}
 
@@ -2871,10 +2924,7 @@ loop:
 			ut_a(node_ptr == page_rec_get_prev(
 				page_get_supremum_rec(father_page)));
 			ut_a(btr_page_get_next(father_page, &mtr) == FIL_NULL);
-		}
-
-		if (right_page_no != FIL_NULL) {
-
+		} else {
 			right_node_ptr = btr_page_get_father_node_ptr(tree,
 							right_page, &mtr);
 			if (page_rec_get_next(node_ptr) !=
@@ -2897,9 +2947,9 @@ loop:
 			} else {
 				right_father_page = buf_frame_align(
 							right_node_ptr);
-							
+
 				if (right_node_ptr != page_rec_get_next(
-					   		page_get_infimum_rec(
+							page_get_infimum_rec(
 							right_father_page))) {
 					ret = FALSE;
 					fputs(
@@ -2931,19 +2981,20 @@ loop:
 					buf_page_print(page);
 					buf_page_print(right_page);
 				}
-			}					
+			}
 		}
 	}
 
 node_ptr_fails:
+	/* Commit the mini-transaction to release the latch on 'page'.
+	Re-acquire the latch on right_page, which will become 'page'
+	on the next loop.  The page has already been checked. */
 	mtr_commit(&mtr);
 
 	if (right_page_no != FIL_NULL) {
-		ulint	comp = page_is_comp(page);
 		mtr_start(&mtr);
-	
+
 		page = btr_page_get(space, right_page_no, RW_X_LATCH, &mtr);
-		ut_a(page_is_comp(page) == comp);
 
 		goto loop;
 	}

--- 1.45.6.1/innobase/buf/buf0buf.c	2006-08-30 15:25:38 +04:00
+++ 1.54/storage/innobase/buf/buf0buf.c	2006-08-30 15:25:38 +04:00
@@ -1,14 +1,14 @@
 /*   Innobase relational database engine; Copyright (C) 2001 Innobase Oy
-     
+
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License 2
      as published by the Free Software Foundation in June 1991.
-     
+
      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 2
      along with this program (in file COPYING); if not, write to the Free
      Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
@@ -42,7 +42,7 @@ Created 11/5/1995 Heikki Tuuri
 		IMPLEMENTATION OF THE BUFFER POOL
 		=================================
 
-Performance improvement: 
+Performance improvement:
 ------------------------
 Thread scheduling in NT may be so slow that the OS wait mechanism should
 not be used even in waiting for disk reads to complete.
@@ -239,33 +239,33 @@ to a file. Note that we must be careful 
 ulint
 buf_calc_page_new_checksum(
 /*=======================*/
-		       /* out: checksum */
-	byte*    page) /* in: buffer page */
+			/* out: checksum */
+	byte*	 page)	/* in: buffer page */
 {
-  	ulint checksum;
+	ulint checksum;
 
-        /* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
-        ..._ARCH_LOG_NO, are written outside the buffer pool to the first
-        pages of data files, we have to skip them in the page checksum
-        calculation.
+	/* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
+	..._ARCH_LOG_NO, are written outside the buffer pool to the first
+	pages of data files, we have to skip them in the page checksum
+	calculation.
 	We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
 	checksum is stored, and also the last 8 bytes of page because
 	there we store the old formula checksum. */
-  	
-  	checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
+
+	checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
 				 FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
-  		   + ut_fold_binary(page + FIL_PAGE_DATA, 
-				           UNIV_PAGE_SIZE - FIL_PAGE_DATA
-				           - FIL_PAGE_END_LSN_OLD_CHKSUM);
-  	checksum = checksum & 0xFFFFFFFFUL;
+		   + ut_fold_binary(page + FIL_PAGE_DATA,
+					   UNIV_PAGE_SIZE - FIL_PAGE_DATA
+					   - FIL_PAGE_END_LSN_OLD_CHKSUM);
+	checksum = checksum & 0xFFFFFFFFUL;
 
-  	return(checksum);
+	return(checksum);
 }
 
 /************************************************************************
 In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only
 looked at the first few bytes of the page. This calculates that old
-checksum. 
+checksum.
 NOTE: we must first store the new formula checksum to
 FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
 because this takes that field as an input! */
@@ -273,16 +273,16 @@ because this takes that field as an inpu
 ulint
 buf_calc_page_old_checksum(
 /*=======================*/
-		       /* out: checksum */
-	byte*    page) /* in: buffer page */
+			/* out: checksum */
+	byte*	 page)	/* in: buffer page */
 {
-  	ulint checksum;
-  	
-  	checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
+	ulint checksum;
+
+	checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
 
-  	checksum = checksum & 0xFFFFFFFFUL;
+	checksum = checksum & 0xFFFFFFFFUL;
 
-  	return(checksum);
+	return(checksum);
 }
 
 /************************************************************************
@@ -302,11 +302,11 @@ buf_page_is_corrupted(
 	dulint	current_lsn;
 #endif
 	if (mach_read_from_4(read_buf + FIL_PAGE_LSN + 4)
-	     != mach_read_from_4(read_buf + UNIV_PAGE_SIZE
-				- FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) {
+		!= mach_read_from_4(read_buf + UNIV_PAGE_SIZE
+			- FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) {
 
 		/* Stored log sequence numbers at the start and the end
-		of page do not match */
+		   of page do not match */
 
 		return(TRUE);
 	}
@@ -314,8 +314,8 @@ buf_page_is_corrupted(
 #ifndef UNIV_HOTBACKUP
 	if (recv_lsn_checks_on && log_peek_lsn(&current_lsn)) {
 		if (ut_dulint_cmp(current_lsn,
-				  mach_read_from_8(read_buf + FIL_PAGE_LSN))
-				 < 0) {
+				mach_read_from_8(read_buf + FIL_PAGE_LSN))
+			< 0) {
 			ut_print_timestamp(stderr);
 
 			fprintf(stderr,
@@ -325,53 +325,58 @@ buf_page_is_corrupted(
 "InnoDB: tablespace but not the InnoDB log files. See\n"
 "InnoDB: http://dev.mysql.com/doc/refman/5.0/en/forcing-recovery.html\n"
 "InnoDB: for more information.\n",
-		        (ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
-			(ulong) ut_dulint_get_high(
-				mach_read_from_8(read_buf + FIL_PAGE_LSN)),
-			(ulong) ut_dulint_get_low(
-				mach_read_from_8(read_buf + FIL_PAGE_LSN)),
-			(ulong) ut_dulint_get_high(current_lsn),
-			(ulong) ut_dulint_get_low(current_lsn));
+				(ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
+				(ulong) ut_dulint_get_high(
+					mach_read_from_8(read_buf + FIL_PAGE_LSN)),
+				(ulong) ut_dulint_get_low(
+					mach_read_from_8(read_buf + FIL_PAGE_LSN)),
+				(ulong) ut_dulint_get_high(current_lsn),
+				(ulong) ut_dulint_get_low(current_lsn));
 		}
 	}
 #endif
-  
-  /* If we use checksums validation, make additional check before returning
-  TRUE to ensure that the checksum is not equal to BUF_NO_CHECKSUM_MAGIC which
-  might be stored by InnoDB with checksums disabled.
-     Otherwise, skip checksum calculation and return FALSE */
-  
-  if (srv_use_checksums) {
-    old_checksum = buf_calc_page_old_checksum(read_buf); 
-
-    old_checksum_field = mach_read_from_4(read_buf + UNIV_PAGE_SIZE
-					- FIL_PAGE_END_LSN_OLD_CHKSUM);
-
-    /* There are 2 valid formulas for old_checksum_field:
-	  1. Very old versions of InnoDB only stored 8 byte lsn to the start
-	  and the end of the page.
-	  2. Newer InnoDB versions store the old formula checksum there. */
-	
-    if (old_checksum_field != mach_read_from_4(read_buf + FIL_PAGE_LSN)
-        && old_checksum_field != old_checksum
-        && old_checksum_field != BUF_NO_CHECKSUM_MAGIC) {
-
-      return(TRUE);
-    }
-
-    checksum = buf_calc_page_new_checksum(read_buf);
-    checksum_field = mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM);
-
-    /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
-	  (always equal to 0), to FIL_PAGE_SPACE_SPACE_OR_CHKSUM */
-
-    if (checksum_field != 0 && checksum_field != checksum
-        && checksum_field != BUF_NO_CHECKSUM_MAGIC) {
-
-      return(TRUE);
-    }
-  }
-  
+
+	/* If we use checksums validation, make additional check before
+	returning TRUE to ensure that the checksum is not equal to
+	BUF_NO_CHECKSUM_MAGIC which might be stored by InnoDB with checksums
+	disabled. Otherwise, skip checksum calculation and return FALSE */
+
+	if (srv_use_checksums) {
+		old_checksum = buf_calc_page_old_checksum(read_buf);
+
+		old_checksum_field = mach_read_from_4(read_buf + UNIV_PAGE_SIZE
+			- FIL_PAGE_END_LSN_OLD_CHKSUM);
+
+		/* There are 2 valid formulas for old_checksum_field:
+
+		1. Very old versions of InnoDB only stored 8 byte lsn to the
+		start and the end of the page.
+
+		2. Newer InnoDB versions store the old formula checksum
+		there. */
+
+		if (old_checksum_field != mach_read_from_4(read_buf
+				+ FIL_PAGE_LSN)
+			&& old_checksum_field != old_checksum
+			&& old_checksum_field != BUF_NO_CHECKSUM_MAGIC) {
+
+			return(TRUE);
+		}
+
+		checksum = buf_calc_page_new_checksum(read_buf);
+		checksum_field = mach_read_from_4(read_buf +
+			FIL_PAGE_SPACE_OR_CHKSUM);
+
+		/* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
+		(always equal to 0), to FIL_PAGE_SPACE_SPACE_OR_CHKSUM */
+
+		if (checksum_field != 0 && checksum_field != checksum
+			&& checksum_field != BUF_NO_CHECKSUM_MAGIC) {
+
+			return(TRUE);
+		}
+	}
+
 	return(FALSE);
 }
 
@@ -394,12 +399,12 @@ buf_page_print(
 	fputs("InnoDB: End of page dump\n", stderr);
 
 	checksum = srv_use_checksums ?
-    buf_calc_page_new_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
+		buf_calc_page_new_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
 	old_checksum = srv_use_checksums ?
-    buf_calc_page_old_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
+		buf_calc_page_old_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
 
 	ut_print_timestamp(stderr);
-	fprintf(stderr, 
+	fprintf(stderr,
 "  InnoDB: Page checksum %lu, prior-to-4.0.14-form checksum %lu\n"
 "InnoDB: stored checksum %lu, prior-to-4.0.14-form stored checksum %lu\n",
 			(ulong) checksum, (ulong) old_checksum,
@@ -418,18 +423,19 @@ buf_page_print(
 		(ulong) mach_read_from_4(read_buf + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
 
 	if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
-	    == TRX_UNDO_INSERT) {
-	    	fprintf(stderr,
+		== TRX_UNDO_INSERT) {
+		fprintf(stderr,
 			"InnoDB: Page may be an insert undo log page\n");
 	} else if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR
 						+ TRX_UNDO_PAGE_TYPE)
-	    	== TRX_UNDO_UPDATE) {
-	    	fprintf(stderr,
+		== TRX_UNDO_UPDATE) {
+		fprintf(stderr,
 			"InnoDB: Page may be an update undo log page\n");
 	}
 
-	if (fil_page_get_type(read_buf) == FIL_PAGE_INDEX) {
-	    	fprintf(stderr,
+	switch (fil_page_get_type(read_buf)) {
+	case FIL_PAGE_INDEX:
+		fprintf(stderr,
 "InnoDB: Page may be an index page where index id is %lu %lu\n",
 			(ulong) ut_dulint_get_high(btr_page_get_index_id(read_buf)),
 			(ulong) ut_dulint_get_low(btr_page_get_index_id(read_buf)));
@@ -439,19 +445,50 @@ buf_page_print(
 
 		if (dict_sys != NULL) {
 
-		        index = dict_index_find_on_id_low(
+			index = dict_index_find_on_id_low(
 					btr_page_get_index_id(read_buf));
-		        if (index) {
+			if (index) {
 				fputs("InnoDB: (", stderr);
 				dict_index_name_print(stderr, NULL, index);
 				fputs(")\n", stderr);
 			}
 		}
-	} else if (fil_page_get_type(read_buf) == FIL_PAGE_INODE) {
+		break;
+	case FIL_PAGE_INODE:
 		fputs("InnoDB: Page may be an 'inode' page\n", stderr);
-	} else if (fil_page_get_type(read_buf) == FIL_PAGE_IBUF_FREE_LIST) {
+		break;
+	case FIL_PAGE_IBUF_FREE_LIST:
 		fputs("InnoDB: Page may be an insert buffer free list page\n",
 			stderr);
+		break;
+	case FIL_PAGE_TYPE_ALLOCATED:
+		fputs("InnoDB: Page may be a freshly allocated page\n",
+			stderr);
+		break;
+	case FIL_PAGE_IBUF_BITMAP:
+		fputs("InnoDB: Page may be an insert buffer bitmap page\n",
+			stderr);
+		break;
+	case FIL_PAGE_TYPE_SYS:
+		fputs("InnoDB: Page may be a system page\n",
+			stderr);
+		break;
+	case FIL_PAGE_TYPE_TRX_SYS:
+		fputs("InnoDB: Page may be a transaction system page\n",
+			stderr);
+		break;
+	case FIL_PAGE_TYPE_FSP_HDR:
+		fputs("InnoDB: Page may be a file space header page\n",
+			stderr);
+		break;
+	case FIL_PAGE_TYPE_XDES:
+		fputs("InnoDB: Page may be an extent descriptor page\n",
+			stderr);
+		break;
+	case FIL_PAGE_TYPE_BLOB:
+		fputs("InnoDB: Page may be a BLOB page\n",
+			stderr);
+		break;
 	}
 }
 
@@ -468,7 +505,7 @@ buf_block_init(
 	block->magic_n = 0;
 
 	block->state = BUF_BLOCK_NOT_USED;
-	
+
 	block->frame = frame;
 
 	block->awe_info = NULL;
@@ -477,7 +514,7 @@ buf_block_init(
 	block->io_fix = 0;
 
 	block->modify_clock = ut_dulint_zero;
-	
+
 	block->file_page_was_freed = FALSE;
 
 	block->check_index_page_at_flush = FALSE;
@@ -488,12 +525,11 @@ buf_block_init(
 
 	block->n_pointers = 0;
 
-	rw_lock_create(&(block->lock));
+	rw_lock_create(&block->lock, SYNC_LEVEL_VARYING);
 	ut_ad(rw_lock_validate(&(block->lock)));
 
 #ifdef UNIV_SYNC_DEBUG
-	rw_lock_create(&(block->debug_latch));
-	rw_lock_set_level(&(block->debug_latch), SYNC_NO_ORDER_CHECK);
+	rw_lock_create(&block->debug_latch, SYNC_NO_ORDER_CHECK);
 #endif /* UNIV_SYNC_DEBUG */
 }
 
@@ -519,12 +555,12 @@ buf_pool_init(
 	byte*		frame;
 	ulint		i;
 	buf_block_t*	block;
-	
+
 	ut_a(max_size == curr_size);
 	ut_a(srv_use_awe || n_frames == max_size);
-	
+
 	if (n_frames > curr_size) {
-	        fprintf(stderr,
+		fprintf(stderr,
 "InnoDB: AWE: Error: you must specify in my.cnf .._awe_mem_mb larger\n"
 "InnoDB: than .._buffer_pool_size. Now the former is %lu pages,\n"
 "InnoDB: the latter %lu pages.\n", (ulong) curr_size, (ulong) n_frames);
@@ -536,8 +572,7 @@ buf_pool_init(
 
 	/* 1. Initialize general fields
 	   ---------------------------- */
-	mutex_create(&(buf_pool->mutex));
-	mutex_set_level(&(buf_pool->mutex), SYNC_BUF_POOL);
+	mutex_create(&buf_pool->mutex, SYNC_BUF_POOL);
 
 	mutex_enter(&(buf_pool->mutex));
 
@@ -548,18 +583,18 @@ buf_pool_init(
 
 		buf_pool->frame_mem = os_awe_allocate_virtual_mem_window(
 					UNIV_PAGE_SIZE * (n_frames + 1));
-					
+
 		/* Allocate the physical memory for AWE and the AWE info array
 		for buf_pool */
 
 		if ((curr_size % ((1024 * 1024) / UNIV_PAGE_SIZE)) != 0) {
 
-		        fprintf(stderr,
+			fprintf(stderr,
 "InnoDB: AWE: Error: physical memory must be allocated in full megabytes.\n"
-"InnoDB: Trying to allocate %lu database pages.\n", 
+"InnoDB: Trying to allocate %lu database pages.\n",
 			  (ulong) curr_size);
 
-		        return(NULL);
+			return(NULL);
 		}
 
 		if (!os_awe_allocate_physical_mem(&(buf_pool->awe_info),
@@ -611,7 +646,7 @@ buf_pool_init(
 	}
 
 	buf_pool->blocks_of_frames = ut_malloc(sizeof(void*) * n_frames);
-	
+
 	if (buf_pool->blocks_of_frames == NULL) {
 
 		return(NULL);
@@ -632,7 +667,7 @@ buf_pool_init(
 		} else {
 			frame = NULL;
 		}
-		
+
 		buf_block_init(block, frame);
 
 		if (srv_use_awe) {
@@ -653,14 +688,14 @@ buf_pool_init(
 	buf_pool->n_pages_written = 0;
 	buf_pool->n_pages_created = 0;
 	buf_pool->n_pages_awe_remapped = 0;
-	
+
 	buf_pool->n_page_gets = 0;
 	buf_pool->n_page_gets_old = 0;
 	buf_pool->n_pages_read_old = 0;
 	buf_pool->n_pages_written_old = 0;
 	buf_pool->n_pages_created_old = 0;
 	buf_pool->n_pages_awe_remapped_old = 0;
-	
+
 	/* 2. Initialize flushing fields
 	   ---------------------------- */
 	UT_LIST_INIT(buf_pool->flush_list);
@@ -675,7 +710,7 @@ buf_pool_init(
 
 	buf_pool->ulint_clock = 1;
 	buf_pool->freed_page_clock = 0;
-	
+
 	/* 3. Initialize LRU fields
 	   ---------------------------- */
 	UT_LIST_INIT(buf_pool->LRU);
@@ -701,7 +736,7 @@ buf_pool_init(
 			if (srv_use_awe) {
 				/* Add to the list of blocks mapped to
 				frames */
-				
+
 				UT_LIST_ADD_LAST(awe_LRU_free_mapped,
 					buf_pool->awe_LRU_free_mapped, block);
 			}
@@ -714,15 +749,15 @@ buf_pool_init(
 	mutex_exit(&(buf_pool->mutex));
 
 	if (srv_use_adaptive_hash_indexes) {
-	  	btr_search_sys_create(
+		btr_search_sys_create(
 			  curr_size * UNIV_PAGE_SIZE / sizeof(void*) / 64);
 	} else {
-	        /* Create only a small dummy system */
-	        btr_search_sys_create(1000);
+		/* Create only a small dummy system */
+		btr_search_sys_create(1000);
 	}
 
 	return(buf_pool);
-}	
+}
 
 /************************************************************************
 Maps the page of block to a frame, if not mapped yet. Unmaps some page
@@ -755,9 +790,9 @@ buf_awe_map_page_to_frame(
 
 	bck = UT_LIST_GET_LAST(buf_pool->awe_LRU_free_mapped);
 
-	while (bck) {	
+	while (bck) {
 		if (bck->state == BUF_BLOCK_FILE_PAGE
-	    	    && (bck->buf_fix_count != 0 || bck->io_fix != 0)) {
+			&& (bck->buf_fix_count != 0 || bck->io_fix != 0)) {
 
 			/* We have to skip this */
 			bck = UT_LIST_GET_PREV(awe_LRU_free_mapped, bck);
@@ -776,7 +811,7 @@ buf_awe_map_page_to_frame(
 						- buf_pool->frame_zero))
 						>> UNIV_PAGE_SIZE_SHIFT))
 				= block;
-			
+
 			bck->frame = NULL;
 			UT_LIST_REMOVE(awe_LRU_free_mapped,
 					buf_pool->awe_LRU_free_mapped,
@@ -789,7 +824,7 @@ buf_awe_map_page_to_frame(
 			}
 
 			buf_pool->n_pages_awe_remapped++;
-			
+
 			return;
 		}
 	}
@@ -828,7 +863,7 @@ buf_block_make_young(
 /*=================*/
 	buf_block_t*	block)	/* in: block to make younger */
 {
-	if (buf_pool->freed_page_clock >= block->freed_page_clock 
+	if (buf_pool->freed_page_clock >= block->freed_page_clock
 				+ 1 + (buf_pool->curr_size / 1024)) {
 
 		/* There has been freeing activity in the LRU list:
@@ -845,11 +880,11 @@ the buffer pool. */
 
 void
 buf_page_make_young(
-/*=================*/
+/*================*/
 	buf_frame_t*	frame)	/* in: buffer frame of a file page */
 {
 	buf_block_t*	block;
-	
+
 	mutex_enter(&(buf_pool->mutex));
 
 	block = buf_block_align(frame);
@@ -899,7 +934,7 @@ buf_frame_free(
 {
 	buf_block_free(buf_block_align(frame));
 }
-	
+
 /************************************************************************
 Returns the buffer control block if the page can be found in the buffer
 pool. NOTE that it is possible that the page is not yet read
@@ -944,7 +979,7 @@ buf_reset_check_index_page_at_flush(
 	if (block) {
 		block->check_index_page_at_flush = FALSE;
 	}
-	
+
 	mutex_exit(&(buf_pool->mutex));
 }
 
@@ -1080,14 +1115,14 @@ buf_page_get_gen(
 	ulint		fix_type;
 	ibool		success;
 	ibool		must_read;
-	
+
 	ut_ad(mtr);
 	ut_ad((rw_latch == RW_S_LATCH)
-	      || (rw_latch == RW_X_LATCH)
-	      || (rw_latch == RW_NO_LATCH));
+		|| (rw_latch == RW_X_LATCH)
+		|| (rw_latch == RW_NO_LATCH));
 	ut_ad((mode != BUF_GET_NO_LATCH) || (rw_latch == RW_NO_LATCH));
 	ut_ad((mode == BUF_GET) || (mode == BUF_GET_IF_IN_POOL)
-	      || (mode == BUF_GET_NO_LATCH) || (mode == BUF_GET_NOWAIT));
+		|| (mode == BUF_GET_NO_LATCH) || (mode == BUF_GET_NOWAIT));
 #ifndef UNIV_LOG_DEBUG
 	ut_ad(!ibuf_inside() || ibuf_page(space, offset));
 #endif
@@ -1096,7 +1131,7 @@ loop:
 	mutex_enter_fast(&(buf_pool->mutex));
 
 	block = NULL;
-	
+
 	if (guess) {
 		block = buf_block_align(guess);
 
@@ -1136,7 +1171,7 @@ loop:
 	ut_a(block->state == BUF_BLOCK_FILE_PAGE);
 
 	must_read = FALSE;
-	
+
 	if (block->io_fix == BUF_IO_READ) {
 
 		must_read = TRUE;
@@ -1148,7 +1183,7 @@ loop:
 
 			return(NULL);
 		}
-	}		
+	}
 
 	/* If AWE is enabled and the page is not mapped to a frame, then
 	map it */
@@ -1159,10 +1194,10 @@ loop:
 		/* We set second parameter TRUE because the block is in the
 		LRU list and we must put it to awe_LRU_free_mapped list once
 		mapped to a frame */
-		
+
 		buf_awe_map_page_to_frame(block, TRUE);
 	}
-	
+
 #ifdef UNIV_SYNC_DEBUG
 	buf_block_buf_fix_inc_debug(block, file, line);
 #else
@@ -1178,7 +1213,7 @@ loop:
 
 #ifdef UNIV_DEBUG_FILE_ACCESSES
 	ut_a(block->file_page_was_freed == FALSE);
-#endif	
+#endif
 	mutex_exit(&(buf_pool->mutex));
 
 #ifdef UNIV_DEBUG
@@ -1209,7 +1244,7 @@ loop:
 			block->buf_fix_count--;
 #ifdef UNIV_SYNC_DEBUG
 			rw_lock_s_unlock(&(block->debug_latch));
-#endif			
+#endif
 			mutex_exit(&(buf_pool->mutex));
 
 			return(NULL);
@@ -1217,24 +1252,24 @@ loop:
 	} else if (rw_latch == RW_NO_LATCH) {
 
 		if (must_read) {
-		        /* Let us wait until the read operation
+			/* Let us wait until the read operation
 			completes */
 
-		        for (;;) {
-			        mutex_enter(&(buf_pool->mutex));
+			for (;;) {
+				mutex_enter(&(buf_pool->mutex));
+
+				if (block->io_fix == BUF_IO_READ) {
 
-		                if (block->io_fix == BUF_IO_READ) {
+					mutex_exit(&(buf_pool->mutex));
 
-				        mutex_exit(&(buf_pool->mutex));
-				  
-				        /* Sleep 20 milliseconds */
+					/* Sleep 20 milliseconds */
 
-				        os_thread_sleep(20000);
+					os_thread_sleep(20000);
 				} else {
-				  
-				       mutex_exit(&(buf_pool->mutex));
 
-				       break;
+					mutex_exit(&(buf_pool->mutex));
+
+					break;
 				}
 			}
 		}
@@ -1263,7 +1298,7 @@ loop:
 #ifdef UNIV_IBUF_DEBUG
 	ut_a(ibuf_count_get(block->space, block->offset) == 0);
 #endif
-	return(block->frame);		
+	return(block->frame);
 }
 
 /************************************************************************
@@ -1290,11 +1325,11 @@ buf_page_optimistic_get_func(
 
 	ut_ad(mtr && block);
 	ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
-	
+
 	mutex_enter(&(buf_pool->mutex));
 
 	/* If AWE is used, block may have a different frame now, e.g., NULL */
-	
+
 	if (UNIV_UNLIKELY(block->state != BUF_BLOCK_FILE_PAGE)
 			|| UNIV_UNLIKELY(block->frame != guess)) {
 	exit_func:
@@ -1332,7 +1367,7 @@ buf_page_optimistic_get_func(
 
 	if (UNIV_UNLIKELY(!success)) {
 		mutex_enter(&(buf_pool->mutex));
-		
+
 		block->buf_fix_count--;
 #ifdef UNIV_SYNC_DEBUG
 		rw_lock_s_unlock(&(block->debug_latch));
@@ -1351,7 +1386,7 @@ buf_page_optimistic_get_func(
 		}
 
 		mutex_enter(&(buf_pool->mutex));
-		
+
 		block->buf_fix_count--;
 #ifdef UNIV_SYNC_DEBUG
 		rw_lock_s_unlock(&(block->debug_latch));
@@ -1412,20 +1447,20 @@ buf_page_get_known_nowait(
 
 	ut_ad(mtr);
 	ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
-	
+
 	mutex_enter(&(buf_pool->mutex));
 
 	block = buf_block_align(guess);
 
 	if (block->state == BUF_BLOCK_REMOVE_HASH) {
-	        /* Another thread is just freeing the block from the LRU list
-	        of the buffer pool: do not try to access this page; this
+		/* Another thread is just freeing the block from the LRU list
+		of the buffer pool: do not try to access this page; this
 		attempt to access the page can only come through the hash
 		index because when the buffer block state is ..._REMOVE_HASH,
 		we have already removed it from the page address hash table
 		of the buffer pool. */
 
-	        mutex_exit(&(buf_pool->mutex));
+		mutex_exit(&(buf_pool->mutex));
 
 		return(FALSE);
 	}
@@ -1454,14 +1489,14 @@ buf_page_get_known_nowait(
 								file, line);
 		fix_type = MTR_MEMO_PAGE_X_FIX;
 	}
-	
+
 	if (!success) {
 		mutex_enter(&(buf_pool->mutex));
-		
+
 		block->buf_fix_count--;
 #ifdef UNIV_SYNC_DEBUG
 		rw_lock_s_unlock(&(block->debug_latch));
-#endif		
+#endif
 		mutex_exit(&(buf_pool->mutex));
 
 		return(FALSE);
@@ -1505,27 +1540,27 @@ buf_page_init_for_backup_restore(
 	/* Set the state of the block */
 	block->magic_n		= BUF_BLOCK_MAGIC_N;
 
-	block->state 		= BUF_BLOCK_FILE_PAGE;
-	block->space 		= space;
-	block->offset 		= offset;
+	block->state		= BUF_BLOCK_FILE_PAGE;
+	block->space		= space;
+	block->offset		= offset;
 
 	block->lock_hash_val	= 0;
 	block->lock_mutex	= NULL;
-	
+
 	block->freed_page_clock = 0;
 
 	block->newest_modification = ut_dulint_zero;
 	block->oldest_modification = ut_dulint_zero;
-	
+
 	block->accessed		= FALSE;
-	block->buf_fix_count 	= 0;
+	block->buf_fix_count	= 0;
 	block->io_fix		= 0;
 
 	block->n_hash_helps	= 0;
 	block->is_hashed	= FALSE;
-	block->n_fields         = 1;
-	block->n_bytes          = 0;
-	block->side             = BTR_SEARCH_LEFT_SIDE;
+	block->n_fields		= 1;
+	block->n_bytes		= 0;
+	block->side		= BTR_SEARCH_LEFT_SIDE;
 
 	block->file_page_was_freed = FALSE;
 }
@@ -1549,31 +1584,31 @@ buf_page_init(
 	/* Set the state of the block */
 	block->magic_n		= BUF_BLOCK_MAGIC_N;
 
-	block->state 		= BUF_BLOCK_FILE_PAGE;
-	block->space 		= space;
-	block->offset 		= offset;
+	block->state		= BUF_BLOCK_FILE_PAGE;
+	block->space		= space;
+	block->offset		= offset;
 
 	block->check_index_page_at_flush = FALSE;
 	block->index		= NULL;
-	
+
 	block->lock_hash_val	= lock_rec_hash(space, offset);
 	block->lock_mutex	= NULL;
-	
+
 	/* Insert into the hash table of file pages */
 
-        if (buf_page_hash_get(space, offset)) {
-                fprintf(stderr,
+	if (buf_page_hash_get(space, offset)) {
+		fprintf(stderr,
 "InnoDB: Error: page %lu %lu already found from the hash table\n",
 			(ulong) space,
 			(ulong) offset);
 #ifdef UNIV_DEBUG
-                buf_print();
-                buf_LRU_print();
-                buf_validate();
-                buf_LRU_validate();
+		buf_print();
+		buf_LRU_print();
+		buf_validate();
+		buf_LRU_validate();
 #endif /* UNIV_DEBUG */
-                ut_a(0);
-        }
+		ut_a(0);
+	}
 
 	HASH_INSERT(buf_block_t, hash, buf_pool->page_hash,
 				buf_page_address_fold(space, offset), block);
@@ -1582,16 +1617,16 @@ buf_page_init(
 
 	block->newest_modification = ut_dulint_zero;
 	block->oldest_modification = ut_dulint_zero;
-	
+
 	block->accessed		= FALSE;
-	block->buf_fix_count 	= 0;
+	block->buf_fix_count	= 0;
 	block->io_fix		= 0;
 
 	block->n_hash_helps	= 0;
 	block->is_hashed	= FALSE;
-	block->n_fields         = 1;
-	block->n_bytes          = 0;
-	block->side             = BTR_SEARCH_LEFT_SIDE;
+	block->n_fields		= 1;
+	block->n_bytes		= 0;
+	block->side		= BTR_SEARCH_LEFT_SIDE;
 
 	block->file_page_was_freed = FALSE;
 }
@@ -1606,7 +1641,7 @@ Sets the io_fix flag to BUF_IO_READ and 
 on the buffer frame. The io-handler must take care that the flag is cleared
 and the lock released later. This is one of the functions which perform the
 state transition NOT_USED => FILE_PAGE to a block (the other is
-buf_page_create). */ 
+buf_page_create). */
 
 buf_block_t*
 buf_page_init_for_read(
@@ -1632,9 +1667,9 @@ buf_page_init_for_read(
 
 		ut_ad(!ibuf_bitmap_page(offset));
 		ut_ad(ibuf_inside());
-	
+
 		mtr_start(&mtr);
-	
+
 		if (!ibuf_page_low(space, offset, &mtr)) {
 
 			mtr_commit(&mtr);
@@ -1644,7 +1679,7 @@ buf_page_init_for_read(
 	} else {
 		ut_ad(mode == BUF_READ_ANY_PAGE);
 	}
-	
+
 	block = buf_block_alloc();
 
 	ut_a(block);
@@ -1657,7 +1692,7 @@ buf_page_init_for_read(
 	}
 
 	if (*err == DB_TABLESPACE_DELETED
-	    || NULL != buf_page_hash_get(space, offset)) {
+		|| NULL != buf_page_hash_get(space, offset)) {
 
 		/* The page belongs to a space which has been deleted or is
 		being deleted, or the page is already in buf_pool, return */
@@ -1674,26 +1709,26 @@ buf_page_init_for_read(
 	}
 
 	ut_ad(block);
-	
+
 	buf_page_init(space, offset, block);
 
 	/* The block must be put to the LRU list, to the old blocks */
 
-	buf_LRU_add_block(block, TRUE); 	/* TRUE == to old blocks */
-	
+	buf_LRU_add_block(block, TRUE);		/* TRUE == to old blocks */
+
 	block->io_fix = BUF_IO_READ;
 	buf_pool->n_pend_reads++;
-	
+
 	/* We set a pass-type x-lock on the frame because then the same
 	thread which called for the read operation (and is running now at
 	this point of code) can wait for the read to complete by waiting
 	for the x-lock on the frame; if the x-lock were recursive, the
 	same thread would illegally get the x-lock before the page read
 	is completed. The x-lock is cleared by the io-handler thread. */
-	
+
 	rw_lock_x_lock_gen(&(block->lock), BUF_IO_READ);
-	
- 	mutex_exit(&(buf_pool->mutex));
+
+	mutex_exit(&(buf_pool->mutex));
 
 	if (mode == BUF_READ_IBUF_PAGES_ONLY) {
 
@@ -1701,7 +1736,7 @@ buf_page_init_for_read(
 	}
 
 	return(block);
-}	
+}
 
 /************************************************************************
 Initializes a page to the buffer buf_pool. The page is usually not read
@@ -1721,11 +1756,11 @@ buf_page_create(
 	buf_frame_t*	frame;
 	buf_block_t*	block;
 	buf_block_t*	free_block	= NULL;
-	
+
 	ut_ad(mtr);
 
 	free_block = buf_LRU_get_free_block();
-	
+
 	mutex_enter(&(buf_pool->mutex));
 
 	block = buf_page_hash_get(space, offset);
@@ -1756,12 +1791,12 @@ buf_page_create(
 #endif /* UNIV_DEBUG */
 
 	block = free_block;
-	
+
 	buf_page_init(space, offset, block);
 
 	/* The block must be put to the LRU list */
 	buf_LRU_add_block(block, FALSE);
-		
+
 #ifdef UNIV_SYNC_DEBUG
 	buf_block_buf_fix_inc_debug(block, __FILE__, __LINE__);
 #else
@@ -1770,7 +1805,7 @@ buf_page_create(
 	mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX);
 
 	block->accessed = TRUE;
-	
+
 	buf_pool->n_pages_created++;
 
 	mutex_exit(&(buf_pool->mutex));
@@ -1785,6 +1820,10 @@ buf_page_create(
 
 	frame = block->frame;
 
+	memset(frame + FIL_PAGE_PREV, 0xff, 4);
+	memset(frame + FIL_PAGE_NEXT, 0xff, 4);
+	mach_write_to_2(frame + FIL_PAGE_TYPE, FIL_PAGE_TYPE_ALLOCATED);
+
 	/* Reset to zero the file flush lsn field in the page; if the first
 	page of an ibdata file is 'created' in this function into the buffer
 	pool then we lose the original contents of the file flush lsn stamp.
@@ -1816,8 +1855,7 @@ buf_page_io_complete(
 	buf_block_t*	block)	/* in: pointer to the block in question */
 {
 	ulint		io_type;
-	ulint		read_page_no;
-	
+
 	ut_ad(block);
 
 	ut_a(block->state == BUF_BLOCK_FILE_PAGE);
@@ -1826,33 +1864,51 @@ buf_page_io_complete(
 
 	if (io_type == BUF_IO_READ) {
 		/* If this page is not uninitialized and not in the
-		doublewrite buffer, then the page number should be the
-		same as in block */
-
-		read_page_no = mach_read_from_4((block->frame)
+		doublewrite buffer, then the page number and space id
+		should be the same as in block. */
+		ulint	read_page_no = mach_read_from_4((block->frame)
 						+ FIL_PAGE_OFFSET);
-		if (read_page_no != 0
-			&& !trx_doublewrite_page_inside(read_page_no)
-	    		&& read_page_no != block->offset) {
+		ulint	read_space_id = mach_read_from_4((block->frame)
+					 + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
 
+		if (!block->space && trx_doublewrite_page_inside(
+				block->offset)) {
+
+			ut_print_timestamp(stderr);
+			fprintf(stderr,
+"  InnoDB: Error: reading page %lu\n"
+"InnoDB: which is in the doublewrite buffer!\n",
+				(ulong) block->offset);
+		} else if (!read_space_id && !read_page_no) {
+			/* This is likely an uninitialized page. */
+		} else if ((block->space && block->space != read_space_id)
+				|| block->offset != read_page_no) {
+			/* We did not compare space_id to read_space_id
+			if block->space == 0, because the field on the
+			page may contain garbage in MySQL < 4.1.1,
+			which only supported block->space == 0. */
+
+			ut_print_timestamp(stderr);
 			fprintf(stderr,
-"InnoDB: Error: page n:o stored in the page read in is %lu, should be %lu!\n",
-				(ulong) read_page_no, (ulong) block->offset);
+"  InnoDB: Error: space id and page n:o stored in the page\n"
+"InnoDB: read in are %lu:%lu, should be %lu:%lu!\n",
+				(ulong) read_space_id, (ulong) read_page_no,
+				(ulong) block->space, (ulong) block->offset);
 		}
 		/* From version 3.23.38 up we store the page checksum
 		   to the 4 first bytes of the page end lsn field */
 
 		if (buf_page_is_corrupted(block->frame)) {
-		  	fprintf(stderr,
+			fprintf(stderr,
 		"InnoDB: Database page corruption on disk or a failed\n"
 		"InnoDB: file read of page %lu.\n", (ulong) block->offset);
-			  
+
 			fputs(
 		"InnoDB: You may have to recover from a backup.\n", stderr);
 
 			buf_page_print(block->frame);
 
-		  	fprintf(stderr,
+			fprintf(stderr,
 		"InnoDB: Database page corruption on disk or a failed\n"
 		"InnoDB: file read of page %lu.\n", (ulong) block->offset);
 			fputs(
@@ -1870,13 +1926,13 @@ buf_page_io_complete(
 		"InnoDB: See also "
 "InnoDB: http://dev.mysql.com/doc/refman/5.0/en/forcing-recovery.html\n"
 		"InnoDB: about forcing recovery.\n", stderr);
-			  
+
 			if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
 				fputs(
 	"InnoDB: Ending processing because of a corrupt database page.\n",
 					stderr);
-		  		exit(1);
-		  	}
+				exit(1);
+			}
 		}
 
 		if (recv_recovery_is_on()) {
@@ -1889,24 +1945,24 @@ buf_page_io_complete(
 					block->space, block->offset, TRUE);
 		}
 	}
-	
+
 #ifdef UNIV_IBUF_DEBUG
 	ut_a(ibuf_count_get(block->space, block->offset) == 0);
 #endif
 	mutex_enter(&(buf_pool->mutex));
-	
+
 	/* Because this thread which does the unlocking is not the same that
 	did the locking, we use a pass value != 0 in unlock, which simply
 	removes the newest lock debug record, without checking the thread
 	id. */
 
 	block->io_fix = 0;
-	
+
 	if (io_type == BUF_IO_READ) {
 		/* NOTE that the call to ibuf may have moved the ownership of
 		the x-latch to this OS thread: do not let this confuse you in
-		debugging! */		
-	
+		debugging! */
+
 		ut_ad(buf_pool->n_pend_reads > 0);
 		buf_pool->n_pend_reads--;
 		buf_pool->n_pages_read++;
@@ -1936,7 +1992,7 @@ buf_page_io_complete(
 		}
 #endif /* UNIV_DEBUG */
 	}
-	
+
 	mutex_exit(&(buf_pool->mutex));
 
 #ifdef UNIV_DEBUG
@@ -1959,13 +2015,13 @@ buf_pool_invalidate(void)
 	ibool	freed;
 
 	ut_ad(buf_all_freed());
-	
+
 	freed = TRUE;
 
 	while (freed) {
 		freed = buf_LRU_search_and_free_block(100);
 	}
-	
+
 	mutex_enter(&(buf_pool->mutex));
 
 	ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0);
@@ -1990,7 +2046,7 @@ buf_validate(void)
 	ulint		n_flush		= 0;
 	ulint		n_free		= 0;
 	ulint		n_page		= 0;
-	
+
 	ut_ad(buf_pool);
 
 	mutex_enter(&(buf_pool->mutex));
@@ -2007,8 +2063,8 @@ buf_validate(void)
 
 #ifdef UNIV_IBUF_DEBUG
 			ut_a((block->io_fix == BUF_IO_READ)
-			     || ibuf_count_get(block->space, block->offset)
-								== 0);
+				|| ibuf_count_get(block->space, block->offset)
+				== 0);
 #endif
 			if (block->io_fix == BUF_IO_WRITE) {
 
@@ -2031,18 +2087,18 @@ buf_validate(void)
 				ut_a(rw_lock_is_locked(&(block->lock),
 							RW_LOCK_EX));
 			}
-			
+
 			n_lru++;
 
 			if (ut_dulint_cmp(block->oldest_modification,
 						ut_dulint_zero) > 0) {
 					n_flush++;
-			}	
-		
+			}
+
 		} else if (block->state == BUF_BLOCK_NOT_USED) {
 			n_free++;
 		}
- 	}
+	}
 
 	if (n_lru + n_free > buf_pool->curr_size) {
 		fprintf(stderr, "n LRU %lu, n free %lu\n", (ulong) n_lru, (ulong) n_free);
@@ -2060,14 +2116,14 @@ buf_validate(void)
 	ut_a(buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE] == n_single_flush);
 	ut_a(buf_pool->n_flush[BUF_FLUSH_LIST] == n_list_flush);
 	ut_a(buf_pool->n_flush[BUF_FLUSH_LRU] == n_lru_flush);
-	
+
 	mutex_exit(&(buf_pool->mutex));
 
 	ut_a(buf_LRU_validate());
 	ut_a(buf_flush_validate());
 
 	return(TRUE);
-}	
+}
 
 /*************************************************************************
 Prints info of the buffer buf_pool data structure. */
@@ -2083,9 +2139,9 @@ buf_print(void)
 	ulint		j;
 	dulint		id;
 	ulint		n_found;
-	buf_frame_t* 	frame;
+	buf_frame_t*	frame;
 	dict_index_t*	index;
-	
+
 	ut_ad(buf_pool);
 
 	size = buf_pool->curr_size;
@@ -2094,7 +2150,7 @@ buf_print(void)
 	counts = mem_alloc(sizeof(ulint) * size);
 
 	mutex_enter(&(buf_pool->mutex));
-	
+
 	fprintf(stderr,
 		"buf_pool size %lu\n"
 		"database pages %lu\n"
@@ -2115,7 +2171,7 @@ buf_print(void)
 		(ulong) buf_pool->n_pages_written);
 
 	/* Count the number of blocks belonging to each index in the buffer */
-	
+
 	n_found = 0;
 
 	for (i = 0; i < size; i++) {
@@ -2153,8 +2209,8 @@ buf_print(void)
 
 		fprintf(stderr,
 			"Block count for index %lu in buffer is about %lu",
-		       (ulong) ut_dulint_get_low(index_ids[i]),
-		       (ulong) counts[i]);
+			(ulong) ut_dulint_get_low(index_ids[i]),
+			(ulong) counts[i]);
 
 		if (index) {
 			putc(' ', stderr);
@@ -2163,12 +2219,12 @@ buf_print(void)
 
 		putc('\n', stderr);
 	}
-	
+
 	mem_free(index_ids);
 	mem_free(counts);
 
 	ut_a(buf_validate());
-}	
+}
 #endif /* UNIV_DEBUG */
 
 /*************************************************************************
@@ -2177,23 +2233,24 @@ Returns the number of latched pages in t
 ulint
 buf_get_latched_pages_number(void)
 {
-        buf_block_t* block;
-        ulint i;
-        ulint fixed_pages_number = 0;
+	buf_block_t* block;
+	ulint i;
+	ulint fixed_pages_number = 0;
 
-        mutex_enter(&(buf_pool->mutex));
+	mutex_enter(&(buf_pool->mutex));
 
-        for (i = 0; i < buf_pool->curr_size; i++) {
+	for (i = 0; i < buf_pool->curr_size; i++) {
 
-               block = buf_pool_get_nth_block(buf_pool, i);
+		block = buf_pool_get_nth_block(buf_pool, i);
+
+		if (((block->buf_fix_count != 0) || (block->io_fix != 0)) &&
+			block->magic_n == BUF_BLOCK_MAGIC_N )
+			fixed_pages_number++;
+	}
 
-               if (((block->buf_fix_count != 0) || (block->io_fix != 0)) &&
-                    block->magic_n == BUF_BLOCK_MAGIC_N )
-                       fixed_pages_number++;
-        }
+	mutex_exit(&(buf_pool->mutex));
 
-        mutex_exit(&(buf_pool->mutex));
-        return fixed_pages_number;
+	return(fixed_pages_number);
 }
 
 /*************************************************************************
@@ -2222,10 +2279,10 @@ buf_get_modified_ratio_pct(void)
 	mutex_enter(&(buf_pool->mutex));
 
 	ratio = (100 * UT_LIST_GET_LEN(buf_pool->flush_list))
-		     / (1 + UT_LIST_GET_LEN(buf_pool->LRU)
-		        + UT_LIST_GET_LEN(buf_pool->free));
+		/ (1 + UT_LIST_GET_LEN(buf_pool->LRU)
+			+ UT_LIST_GET_LEN(buf_pool->free));
 
-		       /* 1 + is there to avoid division by zero */   
+	/* 1 + is there to avoid division by zero */
 
 	mutex_exit(&(buf_pool->mutex));
 
@@ -2243,17 +2300,17 @@ buf_print_io(
 	time_t	current_time;
 	double	time_elapsed;
 	ulint	size;
-	
+
 	ut_ad(buf_pool);
 	size = buf_pool->curr_size;
 
 	mutex_enter(&(buf_pool->mutex));
-	
+
 	if (srv_use_awe) {
 		fprintf(stderr,
 		"AWE: Buffer pool memory frames                        %lu\n",
 				(ulong) buf_pool->n_frames);
-		
+
 		fprintf(stderr,
 		"AWE: Database pages and free buffers mapped in frames %lu\n",
 				(ulong) UT_LIST_GET_LEN(buf_pool->awe_LRU_free_mapped));
@@ -2300,13 +2357,12 @@ buf_print_io(
 				- buf_pool->n_pages_awe_remapped_old)
 			/ time_elapsed);
 	}
-		
+
 	if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) {
 		fprintf(file, "Buffer pool hit rate %lu / 1000\n",
-       (ulong) (1000
-		- ((1000 *
-		    (buf_pool->n_pages_read - buf_pool->n_pages_read_old))
-		/ (buf_pool->n_page_gets - buf_pool->n_page_gets_old))));
+			(ulong) (1000 -
+			((1000 * (buf_pool->n_pages_read - buf_pool->n_pages_read_old))
+			/ (buf_pool->n_page_gets - buf_pool->n_page_gets_old))));
 	} else {
 		fputs("No buffer pool page gets since the last printout\n",
 			file);
@@ -2328,12 +2384,12 @@ void
 buf_refresh_io_stats(void)
 /*======================*/
 {
-        buf_pool->last_printout_time = time(NULL);
+	buf_pool->last_printout_time = time(NULL);
 	buf_pool->n_page_gets_old = buf_pool->n_page_gets;
 	buf_pool->n_pages_read_old = buf_pool->n_pages_read;
 	buf_pool->n_pages_created_old = buf_pool->n_pages_created;
 	buf_pool->n_pages_written_old = buf_pool->n_pages_written;
-	buf_pool->n_pages_awe_remapped_old = buf_pool->n_pages_awe_remapped; 
+	buf_pool->n_pages_awe_remapped_old = buf_pool->n_pages_awe_remapped;
 }
 
 /*************************************************************************
@@ -2345,7 +2401,7 @@ buf_all_freed(void)
 {
 	buf_block_t*	block;
 	ulint		i;
-	
+
 	ut_ad(buf_pool);
 
 	mutex_enter(&(buf_pool->mutex));
@@ -2361,15 +2417,15 @@ buf_all_freed(void)
 				fprintf(stderr,
 					"Page %lu %lu still fixed or dirty\n",
 					(ulong) block->space, (ulong) block->offset);
-			    	ut_error;
+				ut_error;
 			}
 		}
- 	}
+	}
 
 	mutex_exit(&(buf_pool->mutex));
 
 	return(TRUE);
-}	
+}
 
 /*************************************************************************
 Checks that there currently are no pending i/o-operations for the buffer

--- 1.65.11.1/innobase/dict/dict0dict.c	2006-08-30 15:25:38 +04:00
+++ 1.84/storage/innobase/dict/dict0dict.c	2006-08-30 15:25:38 +04:00
@@ -26,6 +26,9 @@ Created 1/8/1996 Heikki Tuuri
 #include "pars0sym.h"
 #include "que0que.h"
 #include "rem0cmp.h"
+#ifndef UNIV_HOTBACKUP
+# include "m_ctype.h" /* my_isspace() */
+#endif /* !UNIV_HOTBACKUP */
 
 dict_sys_t*	dict_sys	= NULL;	/* the dictionary system */
 
@@ -55,6 +58,42 @@ static char	dict_ibfk[] = "_ibfk_";
 
 #ifndef UNIV_HOTBACKUP
 /**********************************************************************
+Converts an identifier to a table name.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+extern
+void
+innobase_convert_from_table_id(
+/*===========================*/
+	char*		to,	/* out: converted identifier */
+	const char*	from,	/* in: identifier to convert */
+	ulint		len);	/* in: length of 'to', in bytes;
+				should be at least 5 * strlen(to) + 1 */
+/**********************************************************************
+Converts an identifier to UTF-8.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+extern
+void
+innobase_convert_from_id(
+/*=====================*/
+	char*		to,	/* out: converted identifier */
+	const char*	from,	/* in: identifier to convert */
+	ulint		len);	/* in: length of 'to', in bytes;
+				should be at least 3 * strlen(to) + 1 */
+/**********************************************************************
+Removes the filename encoding of a table or database name.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+extern
+void
+innobase_convert_from_filename(
+/*===========================*/
+	char*		s);	/* in: identifier; out: decoded identifier */
+/**********************************************************************
 Compares NUL-terminated UTF-8 strings case insensitively.
 
 NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
@@ -77,6 +116,17 @@ void
 innobase_casedn_str(
 /*================*/
 	char*	a);	/* in/out: string to put in lower case */
+
+/**************************************************************************
+Determines the connection character set.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+struct charset_info_st*
+innobase_get_charset(
+/*=================*/
+				/* out: connection character set */
+	void*	mysql_thd);	/* in: MySQL thread handle */
 #endif /* !UNIV_HOTBACKUP */
 
 /**************************************************************************
@@ -132,7 +182,7 @@ dict_index_find_cols(
 /*=================*/
 				/* out: TRUE if success */
 	dict_table_t*	table,	/* in: table */
-	dict_index_t*	index);	/* in: index */	
+	dict_index_t*	index);	/* in: index */
 /***********************************************************************
 Builds the internal dictionary cache representation for a clustered
 index, containing also system fields not defined by the user. */
@@ -144,7 +194,7 @@ dict_index_build_internal_clust(
 				of the clustered index */
 	dict_table_t*	table,	/* in: table */
 	dict_index_t*	index);	/* in: user representation of a clustered
-				index */	
+				index */
 /***********************************************************************
 Builds the internal dictionary cache representation for a non-clustered
 index, containing also system fields not defined by the user. */
@@ -156,7 +206,7 @@ dict_index_build_internal_non_clust(
 				of the non-clustered index */
 	dict_table_t*	table,	/* in: table */
 	dict_index_t*	index);	/* in: user representation of a non-clustered
-				index */	
+				index */
 /**************************************************************************
 Removes a foreign constraint struct from the dictionary cache. */
 static
@@ -196,9 +246,10 @@ dict_foreign_free(
 /* Stream for storing detailed information about the latest foreign key
 and unique key errors */
 FILE*	dict_foreign_err_file		= NULL;
-mutex_t	dict_foreign_err_mutex; 	/* mutex protecting the foreign
+mutex_t	dict_foreign_err_mutex;		/* mutex protecting the foreign
 					and unique error buffers */
-	
+
+#ifndef UNIV_HOTBACKUP
 /**********************************************************************
 Makes all characters in a NUL-terminated UTF-8 string lower case. */
 
@@ -209,6 +260,7 @@ dict_casedn_str(
 {
 	innobase_casedn_str(a);
 }
+#endif /* !UNIV_HOTBACKUP */
 
 /************************************************************************
 Checks if the database name in two table names is the same. */
@@ -233,7 +285,7 @@ dict_tables_have_same_db(
 
 /************************************************************************
 Return the end of table name where we have removed dbname and '/'. */
-static
+
 const char*
 dict_remove_db_name(
 /*================*/
@@ -241,11 +293,10 @@ dict_remove_db_name(
 	const char*	name)	/* in: table name in the form
 				dbname '/' tablename */
 {
-	const char*	s;
-	s = strchr(name, '/');
+	const char*	s = strchr(name, '/');
 	ut_a(s);
-	if (s) s++;
-	return(s);
+
+	return(s + 1);
 }
 
 /************************************************************************
@@ -263,7 +314,7 @@ dict_get_db_name_len(
 	ut_a(s);
 	return(s - name);
 }
-	
+
 /************************************************************************
 Reserves the dictionary system mutex for MySQL. */
 
@@ -273,7 +324,7 @@ dict_mutex_enter_for_mysql(void)
 {
 	mutex_enter(&(dict_sys->mutex));
 }
-	
+
 /************************************************************************
 Releases the dictionary system mutex for MySQL. */
 
@@ -283,7 +334,7 @@ dict_mutex_exit_for_mysql(void)
 {
 	mutex_exit(&(dict_sys->mutex));
 }
-	
+
 /************************************************************************
 Decrements the count of open MySQL handles to a table. */
 
@@ -297,7 +348,7 @@ dict_table_decrement_handle_count(
 	ut_a(table->n_mysql_handles_opened > 0);
 
 	table->n_mysql_handles_opened--;
-	
+
 	mutex_exit(&(dict_sys->mutex));
 }
 
@@ -350,7 +401,7 @@ dict_table_get_index_noninline(
 {
 	return(dict_table_get_index(table, name));
 }
-	
+
 /************************************************************************
 Initializes the autoinc counter. It is not an error to initialize an already
 initialized counter. */
@@ -390,7 +441,7 @@ dict_table_autoinc_get(
 		value = table->autoinc;
 		table->autoinc = table->autoinc + 1;
 	}
-	
+
 	mutex_exit(&(table->autoinc_mutex));
 
 	return(value);
@@ -407,7 +458,7 @@ dict_table_autoinc_decrement(
 	mutex_enter(&(table->autoinc_mutex));
 
 	table->autoinc = table->autoinc - 1;
-	
+
 	mutex_exit(&(table->autoinc_mutex));
 }
 
@@ -431,7 +482,7 @@ dict_table_autoinc_read(
 	} else {
 		value = table->autoinc;
 	}
-	
+
 	mutex_exit(&(table->autoinc_mutex));
 
 	return(value);
@@ -476,7 +527,7 @@ dict_table_autoinc_update(
 		if (value >= table->autoinc) {
 			table->autoinc = value + 1;
 		}
-	}	
+	}
 
 	mutex_exit(&(table->autoinc_mutex));
 }
@@ -497,7 +548,7 @@ dict_index_get_nth_col_pos(
 	dict_col_t*	col;
 	ulint		pos;
 	ulint		n_fields;
-	
+
 	ut_ad(index);
 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
 
@@ -509,7 +560,7 @@ dict_index_get_nth_col_pos(
 	}
 
 	n_fields = dict_index_get_n_fields(index);
-	
+
 	for (pos = 0; pos < n_fields; pos++) {
 		field = dict_index_get_nth_field(index, pos);
 
@@ -537,7 +588,7 @@ dict_index_contains_col_or_prefix(
 	dict_col_t*	col;
 	ulint		pos;
 	ulint		n_fields;
-	
+
 	ut_ad(index);
 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
 
@@ -549,7 +600,7 @@ dict_index_contains_col_or_prefix(
 	col = dict_table_get_nth_col(index->table, n);
 
 	n_fields = dict_index_get_n_fields(index);
-	
+
 	for (pos = 0; pos < n_fields; pos++) {
 		field = dict_index_get_nth_field(index, pos);
 
@@ -582,21 +633,21 @@ dict_index_get_nth_field_pos(
 	dict_field_t*	field2;
 	ulint		n_fields;
 	ulint		pos;
-	
+
 	ut_ad(index);
 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
 
 	field2 = dict_index_get_nth_field(index2, n);
 
 	n_fields = dict_index_get_n_fields(index);
-	
+
 	for (pos = 0; pos < n_fields; pos++) {
 		field = dict_index_get_nth_field(index, pos);
 
 		if (field->col == field2->col
-		    && (field->prefix_len == 0
+			&& (field->prefix_len == 0
 			|| (field->prefix_len >= field2->prefix_len
-			    && field2->prefix_len != 0))) {
+				&& field2->prefix_len != 0))) {
 
 			return(pos);
 		}
@@ -606,7 +657,7 @@ dict_index_get_nth_field_pos(
 }
 
 /**************************************************************************
-Returns a table object, based on table id, and memoryfixes it. */
+Returns a table object based on table id. */
 
 dict_table_t*
 dict_table_get_on_id(
@@ -616,7 +667,7 @@ dict_table_get_on_id(
 	trx_t*	trx)		/* in: transaction handle */
 {
 	dict_table_t*	table;
-	
+
 	if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
 	   || trx->dict_operation_lock_mode == RW_X_LATCH) {
 		/* It is a system table which will always exist in the table
@@ -628,13 +679,13 @@ dict_table_get_on_id(
 		ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 
-		return(dict_table_get_on_id_low(table_id, trx));
+		return(dict_table_get_on_id_low(table_id));
 	}
 
 	mutex_enter(&(dict_sys->mutex));
 
-	table = dict_table_get_on_id_low(table_id, trx);
-	
+	table = dict_table_get_on_id_low(table_id);
+
 	mutex_exit(&(dict_sys->mutex));
 
 	return(table);
@@ -656,6 +707,19 @@ dict_table_get_nth_col_pos(
 }
 
 /************************************************************************
+Check whether the table uses the compact page format. */
+
+ibool
+dict_table_is_comp_noninline(
+/*=========================*/
+					/* out: TRUE if table uses the
+					compact page format */
+	const dict_table_t*	table)	/* in: table */
+{
+	return(dict_table_is_comp(table));
+}
+
+/************************************************************************
 Checks if a column is in the ordering columns of the clustered index of a
 table. Column prefixes are treated like whole columns. */
 
@@ -672,7 +736,7 @@ dict_table_col_in_clustered_key(
 	dict_col_t*	col;
 	ulint		pos;
 	ulint		n_fields;
-	
+
 	ut_ad(table);
 
 	col = dict_table_get_nth_col(table, n);
@@ -680,7 +744,7 @@ dict_table_col_in_clustered_key(
 	index = dict_table_get_first_index(table);
 
 	n_fields = dict_index_get_n_unique(index);
-	
+
 	for (pos = 0; pos < n_fields; pos++) {
 		field = dict_index_get_nth_field(index, pos);
 
@@ -702,8 +766,7 @@ dict_init(void)
 {
 	dict_sys = mem_alloc(sizeof(dict_sys_t));
 
-	mutex_create(&(dict_sys->mutex));
-	mutex_set_level(&(dict_sys->mutex), SYNC_DICT);
+	mutex_create(&dict_sys->mutex, SYNC_DICT);
 
 	dict_sys->table_hash = hash_create(buf_pool_get_max_size() /
 					(DICT_POOL_PER_TABLE_HASH *
@@ -718,44 +781,40 @@ dict_init(void)
 
 	UT_LIST_INIT(dict_sys->table_LRU);
 
-	rw_lock_create(&dict_operation_lock);
-	rw_lock_set_level(&dict_operation_lock, SYNC_DICT_OPERATION);
+	rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
 
 	dict_foreign_err_file = os_file_create_tmpfile();
 	ut_a(dict_foreign_err_file);
-	mutex_create(&dict_foreign_err_mutex);
-	mutex_set_level(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
+
+	mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
 }
 
 /**************************************************************************
-Returns a table object and memoryfixes it. NOTE! This is a high-level
-function to be used mainly from outside the 'dict' directory. Inside this
-directory dict_table_get_low is usually the appropriate function. */
+Returns a table object. NOTE! This is a high-level function to be used
+mainly from outside the 'dict' directory. Inside this directory
+dict_table_get_low is usually the appropriate function. */
 
 dict_table_t*
 dict_table_get(
 /*===========*/
 					/* out: table, NULL if
 					does not exist */
-	const char*	table_name,	/* in: table name */
-	trx_t*		trx)		/* in: transaction handle or NULL */
+	const char*	table_name)	/* in: table name */
 {
 	dict_table_t*	table;
 
-	UT_NOT_USED(trx);
-
 	mutex_enter(&(dict_sys->mutex));
-	
+
 	table = dict_table_get_low(table_name);
 
 	mutex_exit(&(dict_sys->mutex));
 
 	if (table != NULL) {
-	        if (!table->stat_initialized) {
+		if (!table->stat_initialized) {
 			dict_update_statistics(table);
 		}
 	}
-	
+
 	return(table);
 }
 
@@ -767,30 +826,27 @@ dict_table_get_and_increment_handle_coun
 /*======================================*/
 					/* out: table, NULL if
 					does not exist */
-	const char*	table_name,	/* in: table name */
-	trx_t*		trx)		/* in: transaction handle or NULL */
+	const char*	table_name)	/* in: table name */
 {
 	dict_table_t*	table;
 
-	UT_NOT_USED(trx);
-
 	mutex_enter(&(dict_sys->mutex));
-	
+
 	table = dict_table_get_low(table_name);
 
 	if (table != NULL) {
 
-	        table->n_mysql_handles_opened++;
+		table->n_mysql_handles_opened++;
 	}
 
 	mutex_exit(&(dict_sys->mutex));
 
 	if (table != NULL) {
-	        if (!table->stat_initialized && !table->ibd_file_missing) {
+		if (!table->stat_initialized && !table->ibd_file_missing) {
 			dict_update_statistics(table);
 		}
 	}
-	
+
 	return(table);
 }
 
@@ -805,7 +861,8 @@ dict_table_add_to_cache(
 	ulint	fold;
 	ulint	id_fold;
 	ulint	i;
-	
+	ulint	row_len;
+
 	ut_ad(table);
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -813,12 +870,12 @@ dict_table_add_to_cache(
 	ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
 	ut_ad(table->cached == FALSE);
-	
+
 	fold = ut_fold_string(table->name);
 	id_fold = ut_fold_dulint(table->id);
-	
+
 	table->cached = TRUE;
-	
+
 	/* NOTE: the system columns MUST be added in the following order
 	(so that they can be indexed by the numerical value of DATA_ROW_ID,
 	etc.) and as the last columns of the table memory object.
@@ -847,11 +904,29 @@ dict_table_add_to_cache(
 #endif
 
 	/* This check reminds that if a new system column is added to
-	the program, it should be dealt with here */ 
+	the program, it should be dealt with here */
 #if DATA_N_SYS_COLS != 4
 #error "DATA_N_SYS_COLS != 4"
 #endif
 
+	row_len = 0;
+	for (i = 0; i < table->n_def; i++) {
+		ulint	col_len = dtype_get_max_size(
+			dict_col_get_type(dict_table_get_nth_col(table, i)));
+
+		/* If we have a single unbounded field, or several gigantic
+		fields, mark the maximum row size as ULINT_MAX. */
+		if (ut_max(col_len, row_len) >= (ULINT_MAX / 2)) {
+			row_len = ULINT_MAX;
+
+			break;
+		}
+
+		row_len += col_len;
+	}
+
+	table->max_row_size = row_len;
+
 	/* Look for a table with the same name: error if such exists */
 	{
 		dict_table_t*	table2;
@@ -868,13 +943,6 @@ dict_table_add_to_cache(
 		ut_a(table2 == NULL);
 	}
 
-	if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
-
-		table->mix_id_len = mach_dulint_get_compressed_size(
-								table->mix_id);
-		mach_dulint_write_compressed(table->mix_id_buf, table->mix_id);
-	}
-
 	/* Add the columns to the column hash table */
 	for (i = 0; i < table->n_cols; i++) {
 		dict_col_add_to_cache(table, dict_table_get_nth_col(table, i));
@@ -890,10 +958,7 @@ dict_table_add_to_cache(
 	/* Add table to LRU list of tables */
 	UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
 
-	/* If the dictionary cache grows too big, trim the table LRU list */
-
 	dict_sys->size += mem_heap_get_size(table->heap);
-	/* dict_table_LRU_trim(); */
 }
 
 /**************************************************************************
@@ -909,7 +974,7 @@ dict_index_find_on_id_low(
 {
 	dict_table_t*	table;
 	dict_index_t*	index;
-	
+
 	table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
 
 	while (table) {
@@ -951,16 +1016,16 @@ dict_table_rename_in_cache(
 	char*		old_name;
 	ibool		success;
 	ulint		i;
-	
+
 	ut_ad(table);
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 
 	old_size = mem_heap_get_size(table->heap);
-	
+
 	fold = ut_fold_string(new_name);
-	
+
 	/* Look for a table with the same name: error if such exists */
 	{
 		dict_table_t*	table2;
@@ -969,7 +1034,7 @@ dict_table_rename_in_cache(
 		if (table2) {
 			fprintf(stderr,
 "InnoDB: Error: dictionary cache already contains a table of name %s\n",
-	 							     new_name);
+				new_name);
 			return(FALSE);
 		}
 	}
@@ -1018,7 +1083,7 @@ dict_table_rename_in_cache(
 
 	while (index != NULL) {
 		index->table_name = table->name;
-		
+
 		index = dict_table_get_next_index(index);
 	}
 
@@ -1030,7 +1095,7 @@ dict_table_rename_in_cache(
 		constraints from the dictionary cache here. The foreign key
 		constraints will be inherited to the new table from the
 		system tables through a call of dict_load_foreigns. */
-	
+
 		/* Remove the foreign constraints from the cache */
 		foreign = UT_LIST_GET_LAST(table->foreign_list);
 
@@ -1046,14 +1111,14 @@ dict_table_rename_in_cache(
 		while (foreign != NULL) {
 			foreign->referenced_table = NULL;
 			foreign->referenced_index = NULL;
-		
+
 			foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 		}
 
 		/* Make the list of referencing constraints empty */
 
 		UT_LIST_INIT(table->referenced_list);
-		
+
 		return(TRUE);
 	}
 
@@ -1085,10 +1150,10 @@ dict_table_rename_in_cache(
 			old_id = mem_strdup(foreign->id);
 
 			if (ut_strlen(foreign->id) > ut_strlen(old_name)
-						+ ((sizeof dict_ibfk) - 1)
-			    && 0 == ut_memcmp(foreign->id, old_name,
-						ut_strlen(old_name))
-			    && 0 == ut_memcmp(
+				+ ((sizeof dict_ibfk) - 1)
+				&& 0 == ut_memcmp(foreign->id, old_name,
+					ut_strlen(old_name))
+				&& 0 == ut_memcmp(
 					foreign->id + ut_strlen(old_name),
 					dict_ibfk, (sizeof dict_ibfk) - 1)) {
 
@@ -1096,11 +1161,11 @@ dict_table_rename_in_cache(
 
 				if (ut_strlen(table->name) > ut_strlen(old_name)) {
 					foreign->id = mem_heap_alloc(
-					     foreign->heap,
+						foreign->heap,
 						ut_strlen(table->name)
 						+ ut_strlen(old_id) + 1);
 				}
-				
+
 				/* Replace the prefix 'databasename/tablename'
 				with the new names */
 				strcpy(foreign->id, table->name);
@@ -1112,16 +1177,16 @@ dict_table_rename_in_cache(
 				db_len = dict_get_db_name_len(table->name) + 1;
 
 				if (dict_get_db_name_len(table->name)
-			    	    > dict_get_db_name_len(foreign->id)) {
+					> dict_get_db_name_len(foreign->id)) {
 
 					foreign->id = mem_heap_alloc(
-					     foreign->heap,
-				 	     db_len + ut_strlen(old_id) + 1);
+						foreign->heap,
+						db_len + ut_strlen(old_id) + 1);
 				}
 
 				/* Replace the database prefix in id with the
 				one from table->name */
-			
+
 				ut_memcpy(foreign->id, table->name, db_len);
 
 				strcpy(foreign->id + db_len,
@@ -1194,7 +1259,7 @@ dict_table_remove_from_cache(
 	dict_index_t*	index;
 	ulint		size;
 	ulint		i;
-	
+
 	ut_ad(table);
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -1222,7 +1287,7 @@ dict_table_remove_from_cache(
 	while (foreign != NULL) {
 		foreign->referenced_table = NULL;
 		foreign->referenced_index = NULL;
-		
+
 		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 	}
 
@@ -1259,38 +1324,6 @@ dict_table_remove_from_cache(
 }
 
 /**************************************************************************
-Frees tables from the end of table_LRU if the dictionary cache occupies
-too much space. Currently not used! */
-
-void
-dict_table_LRU_trim(void)
-/*=====================*/
-{
-	dict_table_t*	table;
-	dict_table_t*	prev_table;
-
-	ut_error;
-
-#ifdef UNIV_SYNC_DEBUG
-	ut_ad(mutex_own(&(dict_sys->mutex)));
-#endif /* UNIV_SYNC_DEBUG */
-
-	table = UT_LIST_GET_LAST(dict_sys->table_LRU);
-
-	while (table && (dict_sys->size >
-			 buf_pool_get_max_size() / DICT_POOL_PER_VARYING)) {
-
-		prev_table = UT_LIST_GET_PREV(table_LRU, table);
-
-		if (table->mem_fix == 0) {
-			dict_table_remove_from_cache(table);
-		}
-
-		table = prev_table;
-	}
-}
-
-/**************************************************************************
 Adds a column to the data dictionary hash table. */
 static
 void
@@ -1306,7 +1339,7 @@ dict_col_add_to_cache(
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
-	
+
 	fold = ut_fold_ulint_pair(ut_fold_string(table->name),
 				  ut_fold_string(col->name));
 
@@ -1316,7 +1349,7 @@ dict_col_add_to_cache(
 		HASH_SEARCH(hash, dict_sys->col_hash, fold, col2,
 			(ut_strcmp(col->name, col2->name) == 0)
 			&& (ut_strcmp((col2->table)->name, table->name)
-							== 0));  
+							== 0));
 		ut_a(col2 == NULL);
 	}
 
@@ -1339,7 +1372,7 @@ dict_col_remove_from_cache(
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
-	
+
 	fold = ut_fold_ulint_pair(ut_fold_string(table->name),
 				  ut_fold_string(col->name));
 
@@ -1364,7 +1397,7 @@ dict_col_reposition_in_cache(
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
-	
+
 	fold = ut_fold_ulint_pair(ut_fold_string(table->name),
 				  ut_fold_string(col->name));
 
@@ -1372,7 +1405,7 @@ dict_col_reposition_in_cache(
 
 	fold = ut_fold_ulint_pair(ut_fold_string(new_name),
 				  ut_fold_string(col->name));
-				  
+
 	HASH_INSERT(dict_col_t, hash, dict_sys->col_hash, fold, col);
 }
 
@@ -1422,21 +1455,21 @@ dict_index_add_to_cache(
 {
 	dict_index_t*	new_index;
 	dict_tree_t*	tree;
-	dict_table_t*	cluster;
 	dict_field_t*	field;
 	ulint		n_ord;
 	ibool		success;
 	ulint		i;
-	
+
 	ut_ad(index);
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 	ut_ad(index->n_def == index->n_fields);
 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
-	
+
 	ut_ad(mem_heap_validate(index->heap));
 
+#ifdef UNIV_DEBUG
 	{
 		dict_index_t*	index2;
 		index2 = UT_LIST_GET_FIRST(table->indexes);
@@ -1446,10 +1479,11 @@ dict_index_add_to_cache(
 
 			index2 = UT_LIST_GET_NEXT(indexes, index2);
 		}
-
-		ut_a(UT_LIST_GET_LEN(table->indexes) == 0
-	      			|| (index->type & DICT_CLUSTERED) == 0);
 	}
+#endif /* UNIV_DEBUG */
+
+	ut_a(!(index->type & DICT_CLUSTERED)
+			|| UT_LIST_GET_LEN(table->indexes) == 0);
 
 	success = dict_index_find_cols(table, index);
 
@@ -1458,7 +1492,7 @@ dict_index_add_to_cache(
 
 		return(FALSE);
 	}
-	
+
 	/* Build the cache internal representation of the index,
 	containing also the added system fields */
 
@@ -1469,15 +1503,15 @@ dict_index_add_to_cache(
 	}
 
 	new_index->search_info = btr_search_info_create(new_index->heap);
-	
+
 	/* Set the n_fields value in new_index to the actual defined
 	number of fields in the cache internal representation */
 
 	new_index->n_fields = new_index->n_def;
-	
+
 	/* Add the new index as the last index for the table */
 
-	UT_LIST_ADD_LAST(indexes, table->indexes, new_index);	
+	UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
 	new_index->table = table;
 	new_index->table_name = table->name;
 
@@ -1496,21 +1530,11 @@ dict_index_add_to_cache(
 		dict_field_get_col(field)->ord_part++;
 	}
 
-	if (table->type == DICT_TABLE_CLUSTER_MEMBER) {
-		/* The index tree is found from the cluster object */
-	    
-		cluster = dict_table_get_low(table->cluster_name);
-
-		tree = dict_index_get_tree(
-					UT_LIST_GET_FIRST(cluster->indexes));
-		new_index->tree = tree;
-	} else {
-		/* Create an index tree memory object for the index */
-		tree = dict_tree_create(new_index, page_no);
-		ut_ad(tree);
+	/* Create an index tree memory object for the index */
+	tree = dict_tree_create(new_index, page_no);
+	ut_ad(tree);
 
-		new_index->tree = tree;
-	}
+	new_index->tree = tree;
 
 	if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
 
@@ -1526,14 +1550,11 @@ dict_index_add_to_cache(
 			new_index->stat_n_diff_key_vals[i] = 100;
 		}
 	}
-	
+
 	/* Add the index to the list of indexes stored in the tree */
-	UT_LIST_ADD_LAST(tree_indexes, tree->tree_indexes, new_index); 
-	
-	/* If the dictionary cache grows too big, trim the table LRU list */
+	tree->tree_index = new_index;
 
 	dict_sys->size += mem_heap_get_size(new_index->heap);
-	/* dict_table_LRU_trim(); */
 
 	dict_mem_index_free(index);
 
@@ -1560,7 +1581,7 @@ dict_index_remove_from_cache(
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 
-	ut_ad(UT_LIST_GET_LEN((index->tree)->tree_indexes) == 1);
+	ut_ad(index->tree->tree_index);
 	dict_tree_free(index->tree);
 
 	/* Decrement the ord_part counts in columns which are ordering */
@@ -1593,13 +1614,13 @@ dict_index_find_cols(
 /*=================*/
 				/* out: TRUE if success */
 	dict_table_t*	table,	/* in: table */
-	dict_index_t*	index)	/* in: index */	
+	dict_index_t*	index)	/* in: index */
 {
 	dict_col_t*	col;
 	dict_field_t*	field;
 	ulint		fold;
 	ulint		i;
-	
+
 	ut_ad(table && index);
 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
 #ifdef UNIV_SYNC_DEBUG
@@ -1610,15 +1631,15 @@ dict_index_find_cols(
 		field = dict_index_get_nth_field(index, i);
 
 		fold = ut_fold_ulint_pair(ut_fold_string(table->name),
-				  	       ut_fold_string(field->name));
-			
+			ut_fold_string(field->name));
+
 		HASH_SEARCH(hash, dict_sys->col_hash, fold, col,
 				(ut_strcmp(col->name, field->name) == 0)
 				&& (ut_strcmp((col->table)->name, table->name)
-								== 0));  
+								== 0));
 		if (col == NULL) {
 
- 			return(FALSE);
+			return(FALSE);
 		} else {
 			field->col = col;
 		}
@@ -1626,7 +1647,7 @@ dict_index_find_cols(
 
 	return(TRUE);
 }
-	
+
 /***********************************************************************
 Adds a column to index. */
 
@@ -1635,12 +1656,11 @@ dict_index_add_col(
 /*===============*/
 	dict_index_t*	index,		/* in: index */
 	dict_col_t*	col,		/* in: column */
-	ulint		order,		/* in: order criterion */
 	ulint		prefix_len)	/* in: column prefix length */
 {
 	dict_field_t*	field;
 
-	dict_mem_index_add_field(index, col->name, order, prefix_len);
+	dict_mem_index_add_field(index, col->name, prefix_len);
 
 	field = dict_index_get_nth_field(index, index->n_def - 1);
 
@@ -1662,17 +1682,6 @@ dict_index_add_col(
 	if (!(dtype_get_prtype(&col->type) & DATA_NOT_NULL)) {
 		index->n_nullable++;
 	}
-
-	if (index->n_def > 1) {
-		const dict_field_t*	field2 =
-			dict_index_get_nth_field(index, index->n_def - 2);
-		field->fixed_offs = (!field2->fixed_len ||
-					field2->fixed_offs == ULINT_UNDEFINED)
-				? ULINT_UNDEFINED
-				: field2->fixed_len + field2->fixed_offs;
-	} else {
-		field->fixed_offs = 0;
-	}
 }
 
 /***********************************************************************
@@ -1688,14 +1697,13 @@ dict_index_copy(
 {
 	dict_field_t*	field;
 	ulint		i;
-	
+
 	/* Copy fields contained in index2 */
 
 	for (i = start; i < end; i++) {
 
 		field = dict_index_get_nth_field(index2, i);
-		dict_index_add_col(index1, field->col, field->order,
-						      field->prefix_len);
+		dict_index_add_col(index1, field->col, field->prefix_len);
 	}
 }
 
@@ -1740,8 +1748,6 @@ dict_table_copy_types(
 	dtype_t*	type;
 	ulint		i;
 
-	ut_ad(!(table->type & DICT_UNIVERSAL));
-
 	for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
 
 		dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
@@ -1762,7 +1768,7 @@ dict_index_build_internal_clust(
 				of the clustered index */
 	dict_table_t*	table,	/* in: table */
 	dict_index_t*	index)	/* in: user representation of a clustered
-				index */	
+				index */
 {
 	dict_index_t*	new_index;
 	dict_field_t*	field;
@@ -1780,40 +1786,24 @@ dict_index_build_internal_clust(
 
 	/* Create a new index object with certainly enough fields */
 	new_index = dict_mem_index_create(table->name,
-				     index->name,
-				     table->space,
-				     index->type,
-				     index->n_fields + table->n_cols);
+		index->name, table->space, index->type,
+		index->n_fields + table->n_cols);
 
 	/* Copy other relevant data from the old index struct to the new
 	struct: it inherits the values */
 
 	new_index->n_user_defined_cols = index->n_fields;
-	
-	new_index->id = index->id;
 
-	if (table->type != DICT_TABLE_ORDINARY) {
-		/* The index is mixed: copy common key prefix fields */
-		
-		dict_index_copy(new_index, index, 0, table->mix_len);
-
-		/* Add the mix id column */
-		dict_index_add_col(new_index,
-			  dict_table_get_sys_col(table, DATA_MIX_ID), 0, 0);
+	new_index->id = index->id;
 
-		/* Copy the rest of fields */
-		dict_index_copy(new_index, index, table->mix_len,
-							index->n_fields);
-	} else {
-		/* Copy the fields of index */
-		dict_index_copy(new_index, index, 0, index->n_fields);
-	}
+	/* Copy the fields of index */
+	dict_index_copy(new_index, index, 0, index->n_fields);
 
 	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
 		/* No fixed number of fields determines an entry uniquely */
 
 		new_index->n_uniq = ULINT_MAX;
-		
+
 	} else if (index->type & DICT_UNIQUE) {
 		/* Only the fields defined so far are needed to identify
 		the index entry uniquely */
@@ -1831,21 +1821,27 @@ dict_index_build_internal_clust(
 
 		trx_id_pos = new_index->n_def;
 
-		ut_ad(DATA_ROW_ID == 0);
-		ut_ad(DATA_TRX_ID == 1);
-		ut_ad(DATA_ROLL_PTR == 2);
+#if DATA_ROW_ID != 0
+# error "DATA_ROW_ID != 0"
+#endif
+#if DATA_TRX_ID != 1
+# error "DATA_TRX_ID != 1"
+#endif
+#if DATA_ROLL_PTR != 2
+# error "DATA_ROLL_PTR != 2"
+#endif
 
 		if (!(index->type & DICT_UNIQUE)) {
 			dict_index_add_col(new_index,
-			   dict_table_get_sys_col(table, DATA_ROW_ID), 0, 0);
+			   dict_table_get_sys_col(table, DATA_ROW_ID), 0);
 			trx_id_pos++;
 		}
 
 		dict_index_add_col(new_index,
-			   dict_table_get_sys_col(table, DATA_TRX_ID), 0, 0);
-	
+			   dict_table_get_sys_col(table, DATA_TRX_ID), 0);
+
 		dict_index_add_col(new_index,
-			   dict_table_get_sys_col(table, DATA_ROLL_PTR), 0, 0);
+			   dict_table_get_sys_col(table, DATA_ROLL_PTR), 0);
 
 		for (i = 0; i < trx_id_pos; i++) {
 
@@ -1859,7 +1855,7 @@ dict_index_build_internal_clust(
 			}
 
 			if (dict_index_get_nth_field(new_index, i)->prefix_len
-			    > 0) {
+				> 0) {
 				new_index->trx_id_offset = 0;
 
 				break;
@@ -1887,10 +1883,10 @@ dict_index_build_internal_clust(
 
 		if (field->prefix_len == 0) {
 
-		        field->col->aux = 0;
+			field->col->aux = 0;
 		}
 	}
-	
+
 	/* Add to new_index non-system columns of table not yet included
 	there */
 	for (i = 0; i < table->n_cols - DATA_N_SYS_COLS; i++) {
@@ -1899,7 +1895,7 @@ dict_index_build_internal_clust(
 		ut_ad(col->type.mtype != DATA_SYS);
 
 		if (col->aux == ULINT_UNDEFINED) {
-			dict_index_add_col(new_index, col, 0, 0);
+			dict_index_add_col(new_index, col, 0);
 		}
 	}
 
@@ -1914,14 +1910,14 @@ dict_index_build_internal_clust(
 
 		if (field->prefix_len == 0) {
 
-		        field->col->clust_pos = i;
+			field->col->clust_pos = i;
 		}
 	}
-	
+
 	new_index->cached = TRUE;
 
 	return(new_index);
-}	
+}
 
 /***********************************************************************
 Builds the internal dictionary cache representation for a non-clustered
@@ -1934,7 +1930,7 @@ dict_index_build_internal_non_clust(
 				of the non-clustered index */
 	dict_table_t*	table,	/* in: table */
 	dict_index_t*	index)	/* in: user representation of a non-clustered
-				index */	
+				index */
 {
 	dict_field_t*	field;
 	dict_index_t*	new_index;
@@ -1950,24 +1946,21 @@ dict_index_build_internal_non_clust(
 
 	/* The clustered index should be the first in the list of indexes */
 	clust_index = UT_LIST_GET_FIRST(table->indexes);
-	
+
 	ut_ad(clust_index);
 	ut_ad(clust_index->type & DICT_CLUSTERED);
 	ut_ad(!(clust_index->type & DICT_UNIVERSAL));
 
 	/* Create a new index */
 	new_index = dict_mem_index_create(table->name,
-				     index->name,
-				     index->space,
-				     index->type,
-				     index->n_fields
-				     + 1 + clust_index->n_uniq);
+		index->name, index->space, index->type,
+		index->n_fields	+ 1 + clust_index->n_uniq);
 
 	/* Copy other relevant data from the old index
 	struct to the new struct: it inherits the values */
 
 	new_index->n_user_defined_cols = index->n_fields;
-	
+
 	new_index->id = index->id;
 
 	/* Copy fields from index to new_index */
@@ -1991,7 +1984,7 @@ dict_index_build_internal_non_clust(
 
 		if (field->prefix_len == 0) {
 
-		        field->col->aux = 0;
+			field->col->aux = 0;
 		}
 	}
 
@@ -2003,8 +1996,8 @@ dict_index_build_internal_non_clust(
 		field = dict_index_get_nth_field(clust_index, i);
 
 		if (field->col->aux == ULINT_UNDEFINED) {
-			dict_index_add_col(new_index, field->col, 0,
-						      field->prefix_len);
+			dict_index_add_col(new_index, field->col,
+				field->prefix_len);
 		}
 	}
 
@@ -2022,7 +2015,7 @@ dict_index_build_internal_non_clust(
 	new_index->cached = TRUE;
 
 	return(new_index);
-}	
+}
 
 /*====================== FOREIGN KEY PROCESSING ========================*/
 
@@ -2037,7 +2030,7 @@ dict_table_referenced_by_foreign_key(
 	dict_table_t*	table)	/* in: InnoDB table */
 {
 	if (UT_LIST_GET_LEN(table->referenced_list) > 0) {
-		
+
 		return(TRUE);
 	}
 
@@ -2067,7 +2060,7 @@ dict_foreign_remove_from_cache(
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
 	ut_a(foreign);
-	
+
 	if (foreign->referenced_table) {
 		UT_LIST_REMOVE(referenced_list,
 			foreign->referenced_table->referenced_list, foreign);
@@ -2108,7 +2101,7 @@ dict_foreign_find(
 
 		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 	}
-	
+
 	foreign = UT_LIST_GET_FIRST(table->referenced_list);
 
 	while (foreign) {
@@ -2121,8 +2114,9 @@ dict_foreign_find(
 	}
 
 	return(NULL);
-}	
+}
 
+#ifndef UNIV_HOTBACKUP
 /*************************************************************************
 Tries to find an index whose first fields are the columns in the array,
 in the same order. */
@@ -2140,11 +2134,10 @@ dict_foreign_find_index(
 					only has an effect if types_idx !=
 					NULL. */
 {
-#ifndef UNIV_HOTBACKUP
 	dict_index_t*	index;
 	const char*	col_name;
 	ulint		i;
-	
+
 	index = dict_table_get_first_index(table);
 
 	while (index != NULL) {
@@ -2157,22 +2150,22 @@ dict_foreign_find_index(
 						->prefix_len != 0) {
 					/* We do not accept column prefix
 					indexes here */
-					
+
 					break;
 				}
 
 				if (0 != innobase_strcasecmp(columns[i],
 								col_name)) {
-				  	break;
+					break;
 				}
 
 				if (types_idx && !cmp_types_are_equal(
-				     dict_index_get_nth_type(index, i),
-				     dict_index_get_nth_type(types_idx, i),
-				     check_charsets)) {
+					    dict_index_get_nth_type(index, i),
+					    dict_index_get_nth_type(types_idx, i),
+					    check_charsets)) {
 
-				  	break;
-				}		
+					break;
+				}
 			}
 
 			if (i == n_cols) {
@@ -2186,12 +2179,6 @@ dict_foreign_find_index(
 	}
 
 	return(NULL);
-#else /* UNIV_HOTBACKUP */
-	/* This function depends on MySQL code that is not included in
-	InnoDB Hot Backup builds.  Besides, this function should never
-	be called in InnoDB Hot Backup. */
-	ut_error;
-#endif /* UNIV_HOTBACKUP */
 }
 
 /**************************************************************************
@@ -2227,7 +2214,7 @@ dict_foreign_error_report(
 	putc('\n', file);
 	if (fk->foreign_index) {
 		fputs("The index in the foreign key in table is ", file);
-		ut_print_name(file, NULL, fk->foreign_index->name);
+		ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
 		fputs("\n"
 "See http://dev.mysql.com/doc/refman/5.0/en/innodb-foreign-key-constraints.html\n"
 "for correct foreign key definition.\n",
@@ -2255,7 +2242,7 @@ dict_foreign_add_to_cache(
 	dict_foreign_t*	for_in_cache		= NULL;
 	dict_index_t*	index;
 	ibool		added_to_referenced_list= FALSE;
-	FILE*		ef 			= dict_foreign_err_file;
+	FILE*		ef			= dict_foreign_err_file;
 
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -2263,7 +2250,7 @@ dict_foreign_add_to_cache(
 
 	for_table = dict_table_check_if_in_cache_low(
 					foreign->foreign_table_name);
-	
+
 	ref_table = dict_table_check_if_in_cache_low(
 					foreign->referenced_table_name);
 	ut_a(for_table || ref_table);
@@ -2299,7 +2286,7 @@ dict_foreign_add_to_cache(
 				mem_heap_free(foreign->heap);
 			}
 
-		    	return(DB_CANNOT_ADD_CONSTRAINT);
+			return(DB_CANNOT_ADD_CONSTRAINT);
 		}
 
 		for_in_cache->referenced_table = ref_table;
@@ -2328,11 +2315,11 @@ dict_foreign_add_to_cache(
 						ref_table->referenced_list,
 						for_in_cache);
 				}
-			
+
 				mem_heap_free(foreign->heap);
 			}
 
-		    	return(DB_CANNOT_ADD_CONSTRAINT);
+			return(DB_CANNOT_ADD_CONSTRAINT);
 		}
 
 		for_in_cache->foreign_table = for_table;
@@ -2390,12 +2377,13 @@ dict_scan_to(
 
 /*************************************************************************
 Accepts a specified string. Comparisons are case-insensitive. */
-
+static
 const char*
 dict_accept(
 /*========*/
 				/* out: if string was accepted, the pointer
 				is moved after that, else ptr is returned */
+	struct charset_info_st*	cs,/* in: the character set of ptr */
 	const char*	ptr,	/* in: scan from this */
 	const char*	string,	/* in: accept only this string as the next
 				non-whitespace string */
@@ -2405,15 +2393,15 @@ dict_accept(
 	const char*	old_ptr2;
 
 	*success = FALSE;
-	
-	while (isspace(*ptr)) {
+
+	while (my_isspace(cs, *ptr)) {
 		ptr++;
 	}
 
 	old_ptr2 = ptr;
-	
+
 	ptr = dict_scan_to(ptr, string);
-	
+
 	if (*ptr == '\0' || old_ptr2 != ptr) {
 		return(old_ptr);
 	}
@@ -2431,12 +2419,15 @@ const char*
 dict_scan_id(
 /*=========*/
 				/* out: scanned to */
+	struct charset_info_st*	cs,/* in: the character set of ptr */
 	const char*	ptr,	/* in: scanned to */
 	mem_heap_t*	heap,	/* in: heap where to allocate the id
 				(NULL=id will not be allocated, but it
 				will point to string near ptr) */
 	const char**	id,	/* out,own: the id; NULL if no id was
 				scannable */
+	ibool		table_id,/* in: TRUE=convert the allocated id
+				as a table name; FALSE=convert to UTF-8 */
 	ibool		accept_also_dot)
 				/* in: TRUE if also a dot can appear in a
 				non-quoted id; in a quoted id it can appear
@@ -2445,13 +2436,12 @@ dict_scan_id(
 	char		quote	= '\0';
 	ulint		len	= 0;
 	const char*	s;
-	char*		d;
-	ulint		id_len;
-	byte*		b;
+	char*		str;
+	char*		dst;
 
 	*id = NULL;
 
-	while (isspace(*ptr)) {
+	while (my_isspace(cs, *ptr)) {
 		ptr++;
 	}
 
@@ -2482,9 +2472,9 @@ dict_scan_id(
 			len++;
 		}
 	} else {
-		while (!isspace(*ptr) && *ptr != '(' && *ptr != ')'
-		       && (accept_also_dot || *ptr != '.')
-		       && *ptr != ',' && *ptr != '\0') {
+		while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
+			&& (accept_also_dot || *ptr != '.')
+			&& *ptr != ',' && *ptr != '\0') {
 
 			ptr++;
 		}
@@ -2492,43 +2482,50 @@ dict_scan_id(
 		len = ptr - s;
 	}
 
-	if (quote && heap) {
-		*id = d = mem_heap_alloc(heap, len + 1);
+	if (UNIV_UNLIKELY(!heap)) {
+		/* no heap given: id will point to source string */
+		*id = s;
+		return(ptr);
+	}
+
+	if (quote) {
+		char*	d;
+		str = d = mem_heap_alloc(heap, len + 1);
 		while (len--) {
 			if ((*d++ = *s++) == quote) {
 				s++;
 			}
 		}
 		*d++ = 0;
-		ut_a(*s == quote);
-		ut_a(s + 1 == ptr);
-	} else if (heap) {
-		*id = mem_heap_strdupl(heap, s, len);
+		len = d - str;
+		ut_ad(*s == quote);
+		ut_ad(s + 1 == ptr);
 	} else {
-		/* no heap given: id will point to source string */
-		*id = s;
+		str = mem_heap_strdupl(heap, s, len);
 	}
 
-	if (heap && !quote) {
-		/* EMS MySQL Manager sometimes adds characters 0xA0 (in
-		latin1, a 'non-breakable space') to the end of a table name.
-		But isspace(0xA0) is not true, which confuses our foreign key
-		parser. After the UTF-8 conversion in ha_innodb.cc, bytes 0xC2
-		and 0xA0 are at the end of the string.
-
-		TODO: we should lex the string using thd->charset_info, and
-		my_isspace(). Only after that, convert id names to UTF-8. */
-
-		b = (byte*)(*id);
-		id_len = strlen((char*) b);
-		
-		if (id_len >= 3 && b[id_len - 1] == 0xA0
-			       && b[id_len - 2] == 0xC2) {
-
-			/* Strip the 2 last bytes */
+	if (!table_id) {
+convert_id:
+		/* Convert the identifier from connection character set
+		to UTF-8. */
+		len = 3 * len + 1;
+		*id = dst = mem_heap_alloc(heap, len);
+
+		innobase_convert_from_id(dst, str, len);
+	} else if (!strncmp(str, srv_mysql50_table_name_prefix,
+				sizeof srv_mysql50_table_name_prefix)) {
+		/* This is a pre-5.1 table name
+		containing chars other than [A-Za-z0-9].
+		Discard the prefix and use raw UTF-8 encoding. */
+		str += sizeof srv_mysql50_table_name_prefix;
+		len -= sizeof srv_mysql50_table_name_prefix;
+		goto convert_id;
+	} else {
+		/* Encode using filename-safe characters. */
+		len = 5 * len + 1;
+		*id = dst = mem_heap_alloc(heap, len);
 
-			b[id_len - 2] = '\0';
-		}
+		innobase_convert_from_table_id(dst, str, len);
 	}
 
 	return(ptr);
@@ -2541,6 +2538,7 @@ const char*
 dict_scan_col(
 /*==========*/
 				/* out: scanned to */
+	struct charset_info_st*	cs,/* in: the character set of ptr */
 	const char*	ptr,	/* in: scanned to */
 	ibool*		success,/* out: TRUE if success */
 	dict_table_t*	table,	/* in: table in which the column is */
@@ -2549,13 +2547,12 @@ dict_scan_col(
 	const char**	name)	/* out,own: the column name; NULL if no name
 				was scannable */
 {
-#ifndef UNIV_HOTBACKUP
 	dict_col_t*	col;
 	ulint		i;
 
 	*success = FALSE;
 
-	ptr = dict_scan_id(ptr, heap, name, TRUE);
+	ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
 
 	if (*name == NULL) {
 
@@ -2566,29 +2563,23 @@ dict_scan_col(
 		*success = TRUE;
 		*column = NULL;
 	} else {
-	    	for (i = 0; i < dict_table_get_n_cols(table); i++) {
+		for (i = 0; i < dict_table_get_n_cols(table); i++) {
 
 			col = dict_table_get_nth_col(table, i);
 
 			if (0 == innobase_strcasecmp(col->name, *name)) {
-		    		/* Found */
+				/* Found */
 
-		    		*success = TRUE;
-		    		*column = col;
-		    		strcpy((char*) *name, col->name);
+				*success = TRUE;
+				*column = col;
+				strcpy((char*) *name, col->name);
 
-		    		break;
+				break;
 			}
 		}
 	}
-	
+
 	return(ptr);
-#else /* UNIV_HOTBACKUP */
-	/* This function depends on MySQL code that is not included in
-	InnoDB Hot Backup builds.  Besides, this function should never
-	be called in InnoDB Hot Backup. */
-	ut_error;
-#endif /* UNIV_HOTBACKUP */
 }
 
 /*************************************************************************
@@ -2598,6 +2589,7 @@ const char*
 dict_scan_table_name(
 /*=================*/
 				/* out: scanned to */
+	struct charset_info_st*	cs,/* in: the character set of ptr */
 	const char*	ptr,	/* in: scanned to */
 	dict_table_t**	table,	/* out: table object or NULL */
 	const char*	name,	/* in: foreign key table name */
@@ -2606,7 +2598,6 @@ dict_scan_table_name(
 	const char**	ref_name)/* out,own: the table name;
 				NULL if no name was scannable */
 {
-#ifndef UNIV_HOTBACKUP
 	const char*	database_name	= NULL;
 	ulint		database_name_len = 0;
 	const char*	table_name	= NULL;
@@ -2616,11 +2607,11 @@ dict_scan_table_name(
 
 	*success = FALSE;
 	*table = NULL;
-	
-	ptr = dict_scan_id(ptr, heap, &scan_name, FALSE);	
+
+	ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
 
 	if (scan_name == NULL) {
-		
+
 		return(ptr);	/* Syntax error */
 	}
 
@@ -2632,7 +2623,7 @@ dict_scan_table_name(
 		database_name = scan_name;
 		database_name_len = strlen(database_name);
 
-		ptr = dict_scan_id(ptr, heap, &table_name, FALSE);
+		ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
 
 		if (table_name == NULL) {
 
@@ -2688,12 +2679,6 @@ dict_scan_table_name(
 	*table = dict_table_get_low(ref);
 
 	return(ptr);
-#else /* UNIV_HOTBACKUP */
-	/* This function depends on MySQL code that is not included in
-	InnoDB Hot Backup builds.  Besides, this function should never
-	be called in InnoDB Hot Backup. */
-	ut_error;
-#endif /* UNIV_HOTBACKUP */
 }
 
 /*************************************************************************
@@ -2703,20 +2688,21 @@ const char*
 dict_skip_word(
 /*===========*/
 				/* out: scanned to */
+	struct charset_info_st*	cs,/* in: the character set of ptr */
 	const char*	ptr,	/* in: scanned to */
 	ibool*		success)/* out: TRUE if success, FALSE if just spaces
 				left in string or a syntax error */
 {
 	const char*	start;
-	
+
 	*success = FALSE;
 
-	ptr = dict_scan_id(ptr, NULL, &start, TRUE);
+	ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
 
 	if (start) {
 		*success = TRUE;
 	}
-	
+
 	return(ptr);
 }
 
@@ -2738,8 +2724,8 @@ dict_strip_comments(
 	char*		str;
 	const char*	sptr;
 	char*		ptr;
- 	/* unclosed quote character (0 if none) */
- 	char		quote	= 0;
+	/* unclosed quote character (0 if none) */
+	char		quote	= 0;
 
 	str = mem_alloc(strlen(sql_string) + 1);
 
@@ -2767,15 +2753,15 @@ scan_more:
 			/* Starting quote: remember the quote character. */
 			quote = *sptr;
 		} else if (*sptr == '#'
-                           || (sptr[0] == '-' && sptr[1] == '-' &&
-                               sptr[2] == ' ')) {
+			|| (sptr[0] == '-' && sptr[1] == '-' &&
+				sptr[2] == ' ')) {
 			for (;;) {
 				/* In Unix a newline is 0x0A while in Windows
 				it is 0x0D followed by 0x0A */
 
 				if (*sptr == (char)0x0A
-				    || *sptr == (char)0x0D
-				    || *sptr == '\0') {
+					|| *sptr == (char)0x0D
+					|| *sptr == '\0') {
 
 					goto scan_more;
 				}
@@ -2786,7 +2772,7 @@ scan_more:
 			for (;;) {
 				if (*sptr == '*' && *(sptr + 1) == '/') {
 
-				     	sptr += 2;
+					sptr += 2;
 
 					goto scan_more;
 				}
@@ -2832,10 +2818,10 @@ dict_table_get_highest_foreign_id(
 
 	while (foreign) {
 		if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
-		    && 0 == ut_memcmp(foreign->id, table->name, len)
-		    && 0 == ut_memcmp(foreign->id + len,
+			&& 0 == ut_memcmp(foreign->id, table->name, len)
+			&& 0 == ut_memcmp(foreign->id + len,
 				dict_ibfk, (sizeof dict_ibfk) - 1)
-		    && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
+			&& foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
 			/* It is of the >= 4.0.18 format */
 
 			id = strtoul(foreign->id + len + ((sizeof dict_ibfk) - 1),
@@ -2889,6 +2875,7 @@ dict_create_foreign_constraints_low(
 				/* out: error code or DB_SUCCESS */
 	trx_t*		trx,	/* in: transaction */
 	mem_heap_t*	heap,	/* in: memory heap */
+	struct charset_info_st*	cs,/* in: the character set of sql_string */
 	const char*	sql_string,
 				/* in: CREATE TABLE or ALTER TABLE statement
 				where foreign keys are declared like:
@@ -2909,7 +2896,7 @@ dict_create_foreign_constraints_low(
 	ulint		highest_id_so_far	= 0;
 	dict_index_t*	index;
 	dict_foreign_t*	foreign;
- 	const char*	ptr			= sql_string;
+	const char*	ptr			= sql_string;
 	const char*	start_of_latest_foreign	= sql_string;
 	FILE*		ef			= dict_foreign_err_file;
 	const char*	constraint_name;
@@ -2925,7 +2912,7 @@ dict_create_foreign_constraints_low(
 	dict_col_t*	columns[500];
 	const char*	column_names[500];
 	const char*	referenced_table_name;
-	
+
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 #endif /* UNIV_SYNC_DEBUG */
@@ -2946,14 +2933,14 @@ dict_create_foreign_constraints_low(
 	/* First check if we are actually doing an ALTER TABLE, and in that
 	case look for the table being altered */
 
-	ptr = dict_accept(ptr, "ALTER", &success);
+	ptr = dict_accept(cs, ptr, "ALTER", &success);
 
 	if (!success) {
 
 		goto loop;
 	}
 
-	ptr = dict_accept(ptr, "TABLE", &success);
+	ptr = dict_accept(cs, ptr, "TABLE", &success);
 
 	if (!success) {
 
@@ -2962,7 +2949,7 @@ dict_create_foreign_constraints_low(
 
 	/* We are doing an ALTER TABLE: scan the table name we are altering */
 
-	ptr = dict_scan_table_name(ptr, &table_to_alter, name,
+	ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
 				&success, heap, &referenced_table_name);
 	if (!success) {
 		fprintf(stderr,
@@ -3002,21 +2989,22 @@ loop:
 		of the constraint to system tables. */
 		ptr = ptr1;
 
-		ptr = dict_accept(ptr, "CONSTRAINT", &success);
+		ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
 
 		ut_a(success);
 
-		if (!isspace(*ptr) && *ptr != '"' && *ptr != '`') {
-	        	goto loop;
+		if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
+			goto loop;
 		}
 
-		while (isspace(*ptr)) {
+		while (my_isspace(cs, *ptr)) {
 			ptr++;
 		}
 
 		/* read constraint name unless got "CONSTRAINT FOREIGN" */
 		if (ptr != ptr2) {
-			ptr = dict_scan_id(ptr, heap, &constraint_name, FALSE);
+			ptr = dict_scan_id(cs, ptr, heap,
+					&constraint_name, FALSE, FALSE);
 		}
 	} else {
 		ptr = ptr2;
@@ -3030,15 +3018,15 @@ loop:
 		   command, determine if there are any foreign keys, and
 		   if so, immediately reject the command if the table is a
 		   temporary one. For now, this kludge will work. */
-		if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0))
-		{
-			return DB_CANNOT_ADD_CONSTRAINT;
+		if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
+
+			return(DB_CANNOT_ADD_CONSTRAINT);
 		}
-		
+
 		/**********************************************************/
 		/* The following call adds the foreign key constraints
 		to the data dictionary system tables on disk */
-		
+
 		error = dict_create_add_foreigns_to_dictionary(
 						highest_id_so_far, table, trx);
 		return(error);
@@ -3046,28 +3034,28 @@ loop:
 
 	start_of_latest_foreign = ptr;
 
-	ptr = dict_accept(ptr, "FOREIGN", &success);		
-	
+	ptr = dict_accept(cs, ptr, "FOREIGN", &success);
+
 	if (!success) {
 		goto loop;
 	}
 
-	if (!isspace(*ptr)) {
-	        goto loop;
+	if (!my_isspace(cs, *ptr)) {
+		goto loop;
 	}
 
-	ptr = dict_accept(ptr, "KEY", &success);
+	ptr = dict_accept(cs, ptr, "KEY", &success);
 
 	if (!success) {
 		goto loop;
 	}
 
-	ptr = dict_accept(ptr, "(", &success);
+	ptr = dict_accept(cs, ptr, "(", &success);
 
 	if (!success) {
 		/* MySQL allows also an index id before the '('; we
 		skip it */
-		ptr = dict_skip_word(ptr, &success);
+		ptr = dict_skip_word(cs, ptr, &success);
 
 		if (!success) {
 			dict_foreign_report_syntax_err(name,
@@ -3076,13 +3064,13 @@ loop:
 			return(DB_CANNOT_ADD_CONSTRAINT);
 		}
 
-		ptr = dict_accept(ptr, "(", &success);
+		ptr = dict_accept(cs, ptr, "(", &success);
 
 		if (!success) {
 			/* We do not flag a syntax error here because in an
 			ALTER TABLE we may also have DROP FOREIGN KEY abc */
 
-		        goto loop;
+			goto loop;
 		}
 	}
 
@@ -3091,7 +3079,7 @@ loop:
 	/* Scan the columns in the first list */
 col_loop1:
 	ut_a(i < (sizeof column_names) / sizeof *column_names);
-	ptr = dict_scan_col(ptr, &success, table, columns + i,
+	ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
 				heap, column_names + i);
 	if (!success) {
 		mutex_enter(&dict_foreign_err_mutex);
@@ -3104,14 +3092,14 @@ col_loop1:
 	}
 
 	i++;
-	
-	ptr = dict_accept(ptr, ",", &success);
+
+	ptr = dict_accept(cs, ptr, ",", &success);
 
 	if (success) {
 		goto col_loop1;
 	}
-	
-	ptr = dict_accept(ptr, ")", &success);
+
+	ptr = dict_accept(cs, ptr, ")", &success);
 
 	if (!success) {
 		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
@@ -3128,7 +3116,7 @@ col_loop1:
 		mutex_enter(&dict_foreign_err_mutex);
 		dict_foreign_error_report_low(ef, name);
 		fputs("There is no index in table ", ef);
-		ut_print_name(ef, NULL, name);
+		ut_print_name(ef, NULL, TRUE, name);
 		fprintf(ef, " where the columns appear\n"
 "as the first columns. Constraint:\n%s\n"
 "See http://dev.mysql.com/doc/refman/5.0/en/innodb-foreign-key-constraints.html\n"
@@ -3138,9 +3126,9 @@ col_loop1:
 
 		return(DB_CANNOT_ADD_CONSTRAINT);
 	}
-	ptr = dict_accept(ptr, "REFERENCES", &success);
+	ptr = dict_accept(cs, ptr, "REFERENCES", &success);
 
-	if (!success || !isspace(*ptr)) {
+	if (!success || !my_isspace(cs, *ptr)) {
 		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
 									ptr);
 		return(DB_CANNOT_ADD_CONSTRAINT);
@@ -3151,7 +3139,7 @@ col_loop1:
 	foreign = dict_mem_foreign_create();
 
 	if (constraint_name) {
-		ulint	db_len;	
+		ulint	db_len;
 
 		/* Catenate 'databasename/' to the constraint name specified
 		by the user: we conceive the constraint as belonging to the
@@ -3179,8 +3167,8 @@ col_loop1:
 		foreign->foreign_col_names[i] =
 			mem_heap_strdup(foreign->heap, columns[i]->name);
 	}
-	
-	ptr = dict_scan_table_name(ptr, &referenced_table, name,
+
+	ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
 				&success, heap, &referenced_table_name);
 
 	/* Note that referenced_table can be NULL if the user has suppressed
@@ -3198,8 +3186,8 @@ col_loop1:
 
 		return(DB_CANNOT_ADD_CONSTRAINT);
 	}
-	
-	ptr = dict_accept(ptr, "(", &success);
+
+	ptr = dict_accept(cs, ptr, "(", &success);
 
 	if (!success) {
 		dict_foreign_free(foreign);
@@ -3212,10 +3200,10 @@ col_loop1:
 	i = 0;
 
 col_loop2:
-	ptr = dict_scan_col(ptr, &success, referenced_table, columns + i,
+	ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
 				heap, column_names + i);
 	i++;
-	
+
 	if (!success) {
 		dict_foreign_free(foreign);
 
@@ -3229,17 +3217,17 @@ col_loop2:
 		return(DB_CANNOT_ADD_CONSTRAINT);
 	}
 
-	ptr = dict_accept(ptr, ",", &success);
+	ptr = dict_accept(cs, ptr, ",", &success);
 
 	if (success) {
 		goto col_loop2;
 	}
-	
-	ptr = dict_accept(ptr, ")", &success);
+
+	ptr = dict_accept(cs, ptr, ")", &success);
 
 	if (!success || foreign->n_fields != i) {
 		dict_foreign_free(foreign);
-		
+
 		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
 									ptr);
 		return(DB_CANNOT_ADD_CONSTRAINT);
@@ -3247,25 +3235,25 @@ col_loop2:
 
 	n_on_deletes = 0;
 	n_on_updates = 0;
-	
+
 scan_on_conditions:
 	/* Loop here as long as we can find ON ... conditions */
 
-	ptr = dict_accept(ptr, "ON", &success);
+	ptr = dict_accept(cs, ptr, "ON", &success);
 
 	if (!success) {
 
 		goto try_find_index;
 	}
 
-	ptr = dict_accept(ptr, "DELETE", &success);
+	ptr = dict_accept(cs, ptr, "DELETE", &success);
 
 	if (!success) {
-		ptr = dict_accept(ptr, "UPDATE", &success);
+		ptr = dict_accept(cs, ptr, "UPDATE", &success);
 
 		if (!success) {
 			dict_foreign_free(foreign);
-		
+
 			dict_foreign_report_syntax_err(name,
 						start_of_latest_foreign, ptr);
 			return(DB_CANNOT_ADD_CONSTRAINT);
@@ -3278,13 +3266,13 @@ scan_on_conditions:
 		n_on_deletes++;
 	}
 
-	ptr = dict_accept(ptr, "RESTRICT", &success);
+	ptr = dict_accept(cs, ptr, "RESTRICT", &success);
 
 	if (success) {
 		goto scan_on_conditions;
 	}
 
-	ptr = dict_accept(ptr, "CASCADE", &success);
+	ptr = dict_accept(cs, ptr, "CASCADE", &success);
 
 	if (success) {
 		if (is_on_delete) {
@@ -3296,16 +3284,16 @@ scan_on_conditions:
 		goto scan_on_conditions;
 	}
 
-	ptr = dict_accept(ptr, "NO", &success);
+	ptr = dict_accept(cs, ptr, "NO", &success);
 
 	if (success) {
-		ptr = dict_accept(ptr, "ACTION", &success);
+		ptr = dict_accept(cs, ptr, "ACTION", &success);
 
 		if (!success) {
 			dict_foreign_free(foreign);
 			dict_foreign_report_syntax_err(name,
 					start_of_latest_foreign, ptr);
-		
+
 			return(DB_CANNOT_ADD_CONSTRAINT);
 		}
 
@@ -3318,7 +3306,7 @@ scan_on_conditions:
 		goto scan_on_conditions;
 	}
 
-	ptr = dict_accept(ptr, "SET", &success);
+	ptr = dict_accept(cs, ptr, "SET", &success);
 
 	if (!success) {
 		dict_foreign_free(foreign);
@@ -3327,7 +3315,7 @@ scan_on_conditions:
 		return(DB_CANNOT_ADD_CONSTRAINT);
 	}
 
-	ptr = dict_accept(ptr, "NULL", &success);
+	ptr = dict_accept(cs, ptr, "NULL", &success);
 
 	if (!success) {
 		dict_foreign_free(foreign);
@@ -3362,13 +3350,13 @@ scan_on_conditions:
 	} else {
 		foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
 	}
-	
+
 	goto scan_on_conditions;
 
 try_find_index:
 	if (n_on_deletes > 1 || n_on_updates > 1) {
 		/* It is an error to define more than 1 action */
-		
+
 		dict_foreign_free(foreign);
 
 		mutex_enter(&dict_foreign_err_mutex);
@@ -3416,7 +3404,7 @@ try_find_index:
 
 	foreign->referenced_table_name = mem_heap_strdup(foreign->heap,
 						referenced_table_name);
-					
+
 	foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
 							i * sizeof(void*));
 	for (i = 0; i < foreign->n_fields; i++) {
@@ -3425,7 +3413,7 @@ try_find_index:
 	}
 
 	/* We found an ok constraint definition: add to the lists */
-	
+
 	UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
 
 	if (referenced_table) {
@@ -3437,6 +3425,25 @@ try_find_index:
 	goto loop;
 }
 
+/**************************************************************************
+Determines whether a string starts with the specified keyword. */
+
+ibool
+dict_str_starts_with_keyword(
+/*=========================*/
+					/* out: TRUE if str starts
+					with keyword */
+	void*		mysql_thd,	/* in: MySQL thread handle */
+	const char*	str,		/* in: string to scan for keyword */
+	const char*	keyword)	/* in: keyword to look for */
+{
+	struct charset_info_st*	cs	= innobase_get_charset(mysql_thd);
+	ibool			success;
+
+	dict_accept(cs, str, keyword, &success);
+	return(success);
+}
+
 /*************************************************************************
 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
@@ -3464,20 +3471,23 @@ dict_create_foreign_constraints(
 					code DB_CANNOT_ADD_CONSTRAINT if
 					any foreign keys are found. */
 {
-	char*		str;
-	ulint		err;
-	mem_heap_t*	heap;
+	char*			str;
+	ulint			err;
+	mem_heap_t*		heap;
+
+	ut_a(trx && trx->mysql_thd);
 
 	str = dict_strip_comments(sql_string);
 	heap = mem_heap_create(10000);
 
-	err = dict_create_foreign_constraints_low(trx, heap, str, name,
-		reject_fks);
+	err = dict_create_foreign_constraints_low(trx, heap,
+			innobase_get_charset(trx->mysql_thd),
+			str, name, reject_fks);
 
 	mem_heap_free(heap);
 	mem_free(str);
 
-	return(err);	
+	return(err);
 }
 
 /**************************************************************************
@@ -3499,13 +3509,18 @@ dict_foreign_parse_drop_constraints(
 	const char***	constraints_to_drop)	/* out: id's of the
 						constraints to drop */
 {
-	dict_foreign_t*	foreign;
-	ibool		success;
-	char*		str;
-	const char*	ptr;
-	const char*	id;
-	FILE*		ef	= dict_foreign_err_file;
-	
+	dict_foreign_t*		foreign;
+	ibool			success;
+	char*			str;
+	const char*		ptr;
+	const char*		id;
+	FILE*			ef	= dict_foreign_err_file;
+	struct charset_info_st*	cs;
+
+	ut_a(trx && trx->mysql_thd);
+
+	cs = innobase_get_charset(trx->mysql_thd);
+
 	*n = 0;
 
 	*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
@@ -3521,32 +3536,32 @@ loop:
 
 	if (*ptr == '\0') {
 		mem_free(str);
-		
+
 		return(DB_SUCCESS);
 	}
 
-	ptr = dict_accept(ptr, "DROP", &success);
+	ptr = dict_accept(cs, ptr, "DROP", &success);
 
-	if (!isspace(*ptr)) {
+	if (!my_isspace(cs, *ptr)) {
 
-	        goto loop;
+		goto loop;
 	}
 
-	ptr = dict_accept(ptr, "FOREIGN", &success);
-	
+	ptr = dict_accept(cs, ptr, "FOREIGN", &success);
+
 	if (!success) {
 
-	        goto loop;
+		goto loop;
 	}
 
-	ptr = dict_accept(ptr, "KEY", &success);
+	ptr = dict_accept(cs, ptr, "KEY", &success);
 
 	if (!success) {
 
 		goto syntax_error;
 	}
 
-	ptr = dict_scan_id(ptr, heap, &id, TRUE);
+	ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
 
 	if (id == NULL) {
 
@@ -3556,20 +3571,20 @@ loop:
 	ut_a(*n < 1000);
 	(*constraints_to_drop)[*n] = id;
 	(*n)++;
-	
+
 	/* Look for the given constraint id */
 
 	foreign = UT_LIST_GET_FIRST(table->foreign_list);
 
 	while (foreign != NULL) {
 		if (0 == strcmp(foreign->id, id)
-		    || (strchr(foreign->id, '/')
-			&& 0 == strcmp(id,
+			|| (strchr(foreign->id, '/')
+				&& 0 == strcmp(id,
 					dict_remove_db_name(foreign->id)))) {
 			/* Found */
 			break;
 		}
-		
+
 		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 	}
 
@@ -3579,12 +3594,12 @@ loop:
 		ut_print_timestamp(ef);
 		fputs(
 	" Error in dropping of a foreign key constraint of table ", ef);
-		ut_print_name(ef, NULL, table->name);
+		ut_print_name(ef, NULL, TRUE, table->name);
 		fputs(",\n"
 			"in SQL command\n", ef);
 		fputs(str, ef);
 		fputs("\nCannot find a constraint with the given id ", ef);
-		ut_print_name(ef, NULL, id);
+		ut_print_name(ef, NULL, FALSE, id);
 		fputs(".\n", ef);
 		mutex_exit(&dict_foreign_err_mutex);
 
@@ -3593,7 +3608,7 @@ loop:
 		return(DB_CANNOT_DROP_CONSTRAINT);
 	}
 
-	goto loop;	
+	goto loop;
 
 syntax_error:
 	mutex_enter(&dict_foreign_err_mutex);
@@ -3601,7 +3616,7 @@ syntax_error:
 	ut_print_timestamp(ef);
 	fputs(
 	" Syntax error in dropping of a foreign key constraint of table ", ef);
-	ut_print_name(ef, NULL, table->name);
+	ut_print_name(ef, NULL, TRUE, table->name);
 	fprintf(ef, ",\n"
 		"close to:\n%s\n in SQL command\n%s\n", ptr, str);
 	mutex_exit(&dict_foreign_err_mutex);
@@ -3610,6 +3625,7 @@ syntax_error:
 
 	return(DB_CANNOT_DROP_CONSTRAINT);
 }
+#endif /* UNIV_HOTBACKUP */
 
 /*==================== END OF FOREIGN KEY PROCESSING ====================*/
 
@@ -3630,7 +3646,7 @@ dict_index_get_if_in_cache(
 	}
 
 	mutex_enter(&(dict_sys->mutex));
-	
+
 	table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
 
 	while (table) {
@@ -3678,14 +3694,12 @@ dict_tree_create(
 	tree->page = page_no;
 
 	tree->id = index->id;
-	
-	UT_LIST_INIT(tree->tree_indexes);
 
-	tree->magic_n = DICT_TREE_MAGIC_N;
+	tree->tree_index = NULL;
 
-	rw_lock_create(&(tree->lock));
+	tree->magic_n = DICT_TREE_MAGIC_N;
 
-	rw_lock_set_level(&(tree->lock), SYNC_INDEX_TREE);
+	rw_lock_create(&tree->lock, SYNC_INDEX_TREE);
 
 	return(tree);
 }
@@ -3705,135 +3719,7 @@ dict_tree_free(
 	mem_free(tree);
 }
 
-/**************************************************************************
Thread
bk commit into 5.1 tree (anozdrin:1.2285)Alexander Nozdrin30 Aug