List:Commits« Previous MessageNext Message »
From:Marc Alff Date:January 6 2009 7:39pm
Subject:bzr push into mysql-6.0-wl2110-review branch (marc.alff:2722 to 2723)
View as plain text  
 2723 Marc Alff	2009-01-06 [merge]
      Merge mysql-6.0 --> mysql-6.0-wl2110-review
removed:
  mysql-test/t/rpl_slave_exec_mode_basic.test
added:
  config/ac-macros/libmemcached.m4
  config/ac-macros/search_for_lib.m4
  mysql-test/r/innodb_bug34053.result
  mysql-test/t/innodb_bug34053.test
  mysql-test/t/rpl_slave_exec_mode_basic.test
modified:
  BUILD/compile-dist
  BUILD/compile-pentium-gcov
  BUILD/compile-solaris-amd64
  Makefile.am
  configure.in
  libmysqld/examples/test-run
  mysql-test/create-test-result
  mysql-test/mysql-test-run.pl
  mysql-test/r/func_math.result
  mysql-test/r/group_by.result
  mysql-test/r/subselect.result
  mysql-test/r/subselect2.result
  mysql-test/r/subselect3.result
  mysql-test/r/subselect3_jcl6.result
  mysql-test/r/subselect_mat.result
  mysql-test/r/subselect_no_mat.result
  mysql-test/r/subselect_no_opts.result
  mysql-test/r/subselect_no_semijoin.result
  mysql-test/r/subselect_sj.result
  mysql-test/r/subselect_sj2.result
  mysql-test/r/subselect_sj2_jcl6.result
  mysql-test/r/subselect_sj_jcl6.result
  mysql-test/r/type_varchar.result
  mysql-test/t/func_math.test
  mysql-test/t/partition_not_windows.test
  mysql-test/t/subselect.test
  mysql-test/t/subselect3.test
  mysql-test/t/subselect_mat.test
  netware/BUILD/nwbootstrap
  sql/handler.h
  sql/item_cmpfunc.h
  sql/item_func.cc
  sql/item_subselect.cc
  sql/item_subselect.h
  sql/mysql_priv.h
  sql/mysqld.cc
  sql/opt_range.cc
  sql/opt_range.h
  sql/records.h
  sql/sql_base.cc
  sql/sql_class.h
  sql/sql_join_cache.cc
  sql/sql_lex.h
  sql/sql_select.cc
  sql/sql_select.h
  sql/sql_test.cc
  sql/sql_union.cc
  sql/table.h
  storage/archive/support/archive_read_test.slap
  storage/innobase/pars/make_bison.sh
  storage/innobase/pars/make_flex.sh
  storage/maria/ma_test_big.sh
  storage/myisam/mi_test_all.sh
  storage/myisam/myisam_backup_engine.cc
  storage/ndb/demos/run_demo1-PS.sh
  storage/ndb/demos/run_demo1-SS.sh
  support-files/my-small.cnf.sh
  support-files/mysql.spec.sh

 2722 Marc Alff	2008-12-19 [merge]
      Merge mysql-6.0 --> mysql-6.0-wl2110-review
removed:
  .bzr-mysql.moved/
  .bzr-mysql.moved/default.conf
  mysql-test/include/wait_until_disconnected.inc
  mysql-test/r/innodb_bug34053.result
  mysql-test/r/rpl_slave_exec_mode_basic.result
  mysql-test/suite/rpl_ndb_big/r/rpl_ndb_log.result
  mysql-test/suite/rpl_ndb_big/t/rpl_ndb_log-master.opt
  mysql-test/suite/rpl_ndb_big/t/rpl_ndb_log.test
  mysql-test/t/innodb_bug34053.test
  mysql-test/t/rpl_slave_exec_mode_basic.test
added:
  mysql-test/extra/rpl_tests/rpl_row_basic_no_pk.test
  mysql-test/include/UnicodeData.txt
  mysql-test/include/mysqladmin_shutdown.inc
  mysql-test/include/show_qc_status.inc
  mysql-test/include/wait_until_disconnected.inc
  mysql-test/include/world.inc
  mysql-test/include/world_schema.inc
  mysql-test/include/world_schema1.inc
  mysql-test/r/join_cache.result
  mysql-test/r/join_nested_jcl6.result
  mysql-test/r/join_outer_jcl6.result
  mysql-test/r/maria_mrr.result
  mysql-test/r/rpl_slave_allow_batching_basic.result
  mysql-test/r/rpl_slave_compressed_protocol_basic.result
  mysql-test/r/rpl_slave_exec_mode_basic.result
  mysql-test/r/rpl_slave_net_timeout_basic.result
  mysql-test/r/select_jcl6.result
  mysql-test/r/subselect3_jcl6.result
  mysql-test/r/subselect_sj2_jcl6.result
  mysql-test/r/subselect_sj_jcl6.result
  mysql-test/std_data/ndb_apply_status.frm
  mysql-test/suite/backup_engines/r/backup_partition.result
  mysql-test/suite/backup_engines/t/backup_partition.test
  mysql-test/suite/falcon/r/falcon_bug_29246.result
  mysql-test/suite/falcon/r/falcon_bug_34351_A-big.result
  mysql-test/suite/falcon/r/falcon_bug_34351_C-big.result
  mysql-test/suite/falcon/r/falcon_bug_39702.result
  mysql-test/suite/falcon/r/falcon_bug_40614.result
  mysql-test/suite/falcon/r/falcon_bug_40994.result
  mysql-test/suite/falcon/r/falcon_information_schema.result
  mysql-test/suite/falcon/r/falcon_unicode-big.result
  mysql-test/suite/falcon/t/falcon_bug_29246.test
  mysql-test/suite/falcon/t/falcon_bug_34351_A-big.test
  mysql-test/suite/falcon/t/falcon_bug_34351_C-big.test
  mysql-test/suite/falcon/t/falcon_bug_39702.test
  mysql-test/suite/falcon/t/falcon_bug_40614.test
  mysql-test/suite/falcon/t/falcon_bug_40994.test
  mysql-test/suite/falcon/t/falcon_information_schema.test
  mysql-test/suite/falcon/t/falcon_unicode-big.test
  mysql-test/suite/maria/r/maria-recovery3.result
  mysql-test/suite/maria/r/maria_showlog_error.result
  mysql-test/suite/maria/t/maria-recovery3-master.opt
  mysql-test/suite/maria/t/maria-recovery3.test
  mysql-test/suite/maria/t/maria_showlog_error.test
  mysql-test/suite/ndb/r/bug36547.result
  mysql-test/suite/ndb/r/ndb_cache_trans.result
  mysql-test/suite/ndb/r/ndb_dbug_lock.result
  mysql-test/suite/ndb/r/ndb_discover_db.result
  mysql-test/suite/ndb/r/ndb_discover_db2.result
  mysql-test/suite/ndb/t/bug36547.test
  mysql-test/suite/ndb/t/ndb_cache_trans.test
  mysql-test/suite/ndb/t/ndb_dbug_lock.test
  mysql-test/suite/ndb/t/ndb_discover_db.test
  mysql-test/suite/ndb/t/ndb_discover_db2-master.opt
  mysql-test/suite/ndb/t/ndb_discover_db2.test
  mysql-test/suite/ndb_binlog/
  mysql-test/suite/ndb_binlog/r/
  mysql-test/suite/ndb_binlog/r/ndb_binlog_restore.result
  mysql-test/suite/ndb_binlog/t/
  mysql-test/suite/ndb_binlog/t/ndb_binlog_restore-master.opt
  mysql-test/suite/ndb_binlog/t/ndb_binlog_restore.test
  mysql-test/suite/parts/r/partition_alter2_1_maria.result
  mysql-test/suite/parts/r/partition_alter2_2_maria.result
  mysql-test/suite/parts/r/partition_auto_increment_maria.result
  mysql-test/suite/parts/t/partition_alter2_1_maria.test
  mysql-test/suite/parts/t/partition_alter2_2_maria.test
  mysql-test/suite/parts/t/partition_auto_increment_maria.test
  mysql-test/suite/rpl/r/rpl_extraCol_falcon.result
  mysql-test/suite/rpl/r/rpl_extraColmaster_falcon.result
  mysql-test/suite/rpl/r/rpl_locktrans_falcon.result
  mysql-test/suite/rpl/r/rpl_relay_space_falcon.result
  mysql-test/suite/rpl/r/rpl_row_blob_falcon.result
  mysql-test/suite/rpl/r/rpl_truncate_falcon.result
  mysql-test/suite/rpl/t/rpl_extraCol_falcon.test
  mysql-test/suite/rpl/t/rpl_extraColmaster_falcon.test
  mysql-test/suite/rpl/t/rpl_locktrans_falcon.test
  mysql-test/suite/rpl/t/rpl_relay_space_falcon.test
  mysql-test/suite/rpl/t/rpl_row_blob_falcon.test
  mysql-test/suite/rpl/t/rpl_truncate_falcon.test
  mysql-test/suite/rpl_ndb/r/rpl_ndb_bug22045.result
  mysql-test/suite/rpl_ndb/t/rpl_ndb_bug22045.test
  mysql-test/t/join_cache.test
  mysql-test/t/join_nested_jcl6.test
  mysql-test/t/join_outer_jcl6.test
  mysql-test/t/maria_mrr.test
  mysql-test/t/rpl_slave_allow_batching_basic.test
  mysql-test/t/rpl_slave_compressed_protocol_basic.test
  mysql-test/t/rpl_slave_exec_mode_basic.test
  mysql-test/t/rpl_slave_net_timeout_basic.test
  mysql-test/t/select_jcl6.test
  mysql-test/t/subselect3_jcl6.test
  mysql-test/t/subselect_sj2_jcl6.test
  mysql-test/t/subselect_sj_jcl6.test
  mysys/tests/
  mysys/tests/Makefile.am
  mysys/tests/test_thr_mutex.c
  sql/backup/debug.h
  sql/ha_ndbcluster_lock_ext.h
  sql/sql_join_cache.cc
  storage/falcon/CompareAndSwapSparc.h
  storage/ndb/include/util/NdbTap.hpp
  storage/ndb/ndbapi-examples/ndbapi_recattr_vs_record/
  storage/ndb/ndbapi-examples/ndbapi_recattr_vs_record/Makefile
  storage/ndb/ndbapi-examples/ndbapi_recattr_vs_record/main.cpp
  storage/ndb/src/common/util/ndb_show_compat.cpp
  storage/ndb/swig/
  storage/ndb/swig/Makefile.am
  storage/ndb/swig/globals.i
  storage/ndb/swig/mgmapi/
  storage/ndb/swig/mgmapi/ClusterState.i
  storage/ndb/swig/mgmapi/NdbLogEvent.i
  storage/ndb/swig/mgmapi/NdbLogEventManager.i
  storage/ndb/swig/mgmapi/NdbMgm.i
  storage/ndb/swig/mgmapi/NdbMgmFactory.i
  storage/ndb/swig/mgmapi/NdbMgmReply.i
  storage/ndb/swig/mgmapi/NodeState.i
  storage/ndb/swig/mgmapi/events.i
  storage/ndb/swig/mgmapi/listeners.i
  storage/ndb/swig/mgmapi/mgmglobals.i
  storage/ndb/swig/ndbapi/
  storage/ndb/swig/ndbapi/Ndb.i
  storage/ndb/swig/ndbapi/NdbBlob.i
  storage/ndb/swig/ndbapi/NdbClusterConnection.i
  storage/ndb/swig/ndbapi/NdbDictionary.i
  storage/ndb/swig/ndbapi/NdbError.i
  storage/ndb/swig/ndbapi/NdbEventOperation.i
  storage/ndb/swig/ndbapi/NdbFactory.i
  storage/ndb/swig/ndbapi/NdbIndexOperation.i
  storage/ndb/swig/ndbapi/NdbIndexScanOperation.i
  storage/ndb/swig/ndbapi/NdbOperation.i
  storage/ndb/swig/ndbapi/NdbRecAttr.i
  storage/ndb/swig/ndbapi/NdbScanFilter.i
  storage/ndb/swig/ndbapi/NdbScanOperation.i
  storage/ndb/swig/ndbapi/NdbTransaction.i
  storage/ndb/swig/ndbapi/ndbglobals.i
  storage/ndb/test/include/SqlClient.hpp
  storage/ndb/test/ndbapi/testUpgrade.cpp
  storage/ndb/test/run-test/atrt-backtrace.sh
  storage/ndb/test/run-test/command.cpp
  storage/ndb/test/run-test/db.cpp
  storage/ndb/test/run-test/db.sql
  storage/ndb/test/src/SqlClient.cpp
renamed:
  mysql-test/r/rpl_slave_allow_batching_basic.result => mysql-test/r/slave_allow_batching_basic.result
  mysql-test/r/rpl_slave_compressed_protocol_basic.result => mysql-test/r/slave_compressed_protocol_basic.result
  mysql-test/r/rpl_slave_net_timeout_basic.result => mysql-test/r/slave_net_timeout_basic.result
  mysql-test/suite/funcs_1/r/is_collation_charset_applic.result => mysql-test/suite/funcs_1/r/is_collation_character_set_applicability.result
  mysql-test/suite/funcs_1/t/is_collation_charset_applic.test => mysql-test/suite/funcs_1/t/is_collation_character_set_applicability.test
  mysql-test/suite/ndb/r/ndb_binlog_basic.result => mysql-test/suite/ndb_binlog/r/ndb_binlog_basic.result
  mysql-test/suite/ndb/r/ndb_binlog_ddl_multi.result => mysql-test/suite/ndb_binlog/r/ndb_binlog_ddl_multi.result
  mysql-test/suite/ndb/r/ndb_binlog_discover.result => mysql-test/suite/ndb_binlog/r/ndb_binlog_discover.result
  mysql-test/suite/ndb/r/ndb_binlog_ignore_db.result => mysql-test/suite/ndb_binlog/r/ndb_binlog_ignore_db.result
  mysql-test/suite/ndb/r/ndb_binlog_log_bin.result => mysql-test/suite/ndb_binlog/r/ndb_binlog_log_bin.result
  mysql-test/suite/ndb/r/ndb_binlog_multi.result => mysql-test/suite/ndb_binlog/r/ndb_binlog_multi.result
  mysql-test/suite/ndb/t/ndb_binlog_basic.test => mysql-test/suite/ndb_binlog/t/ndb_binlog_basic.test
  mysql-test/suite/ndb/t/ndb_binlog_ddl_multi.test => mysql-test/suite/ndb_binlog/t/ndb_binlog_ddl_multi.test
  mysql-test/suite/ndb/t/ndb_binlog_discover.test => mysql-test/suite/ndb_binlog/t/ndb_binlog_discover.test
  mysql-test/suite/ndb/t/ndb_binlog_ignore_db-master.opt => mysql-test/suite/ndb_binlog/t/ndb_binlog_ignore_db-master.opt
  mysql-test/suite/ndb/t/ndb_binlog_ignore_db.test => mysql-test/suite/ndb_binlog/t/ndb_binlog_ignore_db.test
  mysql-test/suite/ndb/t/ndb_binlog_log_bin.test => mysql-test/suite/ndb_binlog/t/ndb_binlog_log_bin.test
  mysql-test/suite/ndb/t/ndb_binlog_multi.test => mysql-test/suite/ndb_binlog/t/ndb_binlog_multi.test
  mysql-test/suite/ndb_team/r/ndb_binlog_format.result => mysql-test/suite/ndb_binlog/r/ndb_binlog_format.result
  mysql-test/suite/ndb_team/r/ndb_dd_restore_compat.result => mysql-test/suite/ndb/r/ndb_dd_restore_compat.result
  mysql-test/suite/ndb_team/t/ndb_binlog_format.test => mysql-test/suite/ndb_binlog/t/ndb_binlog_format.test
  mysql-test/suite/ndb_team/t/ndb_dd_restore_compat.test => mysql-test/suite/ndb/t/ndb_dd_restore_compat.test
  mysql-test/suite/rpl_ndb_big/r/rpl_ndb_add_column.result => mysql-test/suite/rpl_ndb/r/rpl_ndb_add_column.result
  mysql-test/suite/rpl_ndb_big/t/rpl_ndb_add_column.test => mysql-test/suite/rpl_ndb/t/rpl_ndb_add_column.test
  mysql-test/t/rpl_slave_allow_batching_basic.test => mysql-test/t/slave_allow_batching_basic.test
  mysql-test/t/rpl_slave_compressed_protocol_basic.test => mysql-test/t/slave_compressed_protocol_basic.test
  mysql-test/t/rpl_slave_net_timeout_basic.test => mysql-test/t/slave_net_timeout_basic.test
  mysys/test_charset.c => mysys/tests/test_charset.c
  mysys/test_dir.c => mysys/tests/test_dir.c
  mysys/testhash.c => mysys/tests/testhash.c
  storage/ndb/src/common/util/ndb_init.c => storage/ndb/src/common/util/ndb_init.cpp
modified:
  .bzrignore
  BUILD/SETUP.sh
  BUILD/autorun.sh
  CMakeLists.txt
  Makefile.am
  client/CMakeLists.txt
  client/Makefile.am
  client/mysql.cc
  client/mysqladmin.cc
  client/mysqldump.c
  client/mysqlimport.c
  client/mysqlshow.c
  client/mysqlslap.c
  client/mysqltest.c
  cluster_change_hist.txt
  config/ac-macros/ha_ndbcluster.m4
  config/ac-macros/misc.m4
  config/ac-macros/zlib.m4
  configure.in
  dbug/CMakeLists.txt
  dbug/Makefile.am
  dbug/dbug.c
  extra/CMakeLists.txt
  extra/Makefile.am
  include/config-win.h
  include/hash.h
  include/my_base.h
  include/my_pthread.h
  include/mysql.h.pp
  include/mysql_com.h
  include/thr_lock.h
  include/waiting_threads.h
  libmysql/CMakeLists.txt
  libmysql/Makefile.am
  libmysql/Makefile.shared
  libmysqld/CMakeLists.txt
  libmysqld/Makefile.am
  libmysqld/examples/CMakeLists.txt
  libmysqld/examples/Makefile.am
  mysql-test/extra/rpl_tests/rpl_row_basic.test
  mysql-test/extra/rpl_tests/rpl_truncate_helper.test
  mysql-test/include/have_blackhole.inc
  mysql-test/include/maria_empty_logs.inc
  mysql-test/include/restart_mysqld.inc
  mysql-test/include/wait_until_connected_again.inc
  mysql-test/lib/mtr_cases.pl
  mysql-test/lib/mtr_report.pl
  mysql-test/mysql-test-run.pl
  mysql-test/r/compress.result
  mysql-test/r/fulltext.result
  mysql-test/r/index_merge_myisam.result
  mysql-test/r/join_nested.result
  mysql-test/r/join_outer.result
  mysql-test/r/myisam_mrr.result
  mysql-test/r/named_pipe.result
  mysql-test/r/order_by.result
  mysql-test/r/pool_of_threads.result
  mysql-test/r/select.result
  mysql-test/r/shm.result
  mysql-test/r/signal.result
  mysql-test/r/signal_demo3.result
  mysql-test/r/signal_utf32.result
  mysql-test/r/sp-error.result
  mysql-test/r/ssl.result
  mysql-test/r/ssl_compress.result
  mysql-test/r/subselect3.result
  mysql-test/r/subselect_sj.result
  mysql-test/r/subselect_sj2.result
  mysql-test/r/view.result
  mysql-test/suite/backup/r/backup.result
  mysql-test/suite/backup/r/backup_backupdir.result
  mysql-test/suite/backup/r/backup_default.result
  mysql-test/suite/backup/r/backup_errors.result
  mysql-test/suite/backup/r/backup_views.result
  mysql-test/suite/backup/t/backup.test
  mysql-test/suite/backup/t/backup_backupdir.test
  mysql-test/suite/backup/t/backup_default.test
  mysql-test/suite/backup/t/backup_errors.test
  mysql-test/suite/backup/t/backup_myisam1.test
  mysql-test/suite/backup/t/backup_views.test
  mysql-test/suite/backup/t/disabled.def
  mysql-test/suite/binlog/r/binlog_multi_engine.result
  mysql-test/suite/falcon/r/falcon_bug_22089.result
  mysql-test/suite/falcon/r/falcon_bug_22181.result
  mysql-test/suite/falcon/r/falcon_bug_34351_A.result
  mysql-test/suite/falcon/r/falcon_bug_34351_C.result
  mysql-test/suite/falcon/r/falcon_bug_39708.result
  mysql-test/suite/falcon/r/falcon_online_index.result
  mysql-test/suite/falcon/r/falcon_options.result
  mysql-test/suite/falcon/r/falcon_options2.result
  mysql-test/suite/falcon/r/falcon_select.result
  mysql-test/suite/falcon/r/index_merge_falcon.result
  mysql-test/suite/falcon/t/disabled.def
  mysql-test/suite/falcon/t/falcon_bug_22089.test
  mysql-test/suite/falcon/t/falcon_bug_22181.test
  mysql-test/suite/falcon/t/falcon_bug_28095.test
  mysql-test/suite/falcon/t/falcon_bug_34351_A.test
  mysql-test/suite/falcon/t/falcon_bug_34351_C.test
  mysql-test/suite/falcon/t/falcon_bug_39708-master.opt
  mysql-test/suite/falcon/t/falcon_bug_39708.test
  mysql-test/suite/falcon/t/falcon_options.test
  mysql-test/suite/falcon/t/falcon_options2.test
  mysql-test/suite/funcs_1/r/ndb_trig_1011ext.result
  mysql-test/suite/funcs_1/r/processlist_val_ps.result
  mysql-test/suite/funcs_1/t/disabled.def
  mysql-test/suite/funcs_2/t/disabled.def
  mysql-test/suite/maria/r/maria-big.result
  mysql-test/suite/maria/r/maria-preload.result
  mysql-test/suite/maria/r/maria-recovery-big.result
  mysql-test/suite/maria/r/maria.result
  mysql-test/suite/maria/r/maria3.result
  mysql-test/suite/maria/r/maria_notembedded.result
  mysql-test/suite/maria/t/maria-big.test
  mysql-test/suite/maria/t/maria-lock.test
  mysql-test/suite/maria/t/maria-recovery-big-master.opt
  mysql-test/suite/maria/t/maria-recovery-big.test
  mysql-test/suite/maria/t/maria.test
  mysql-test/suite/maria/t/maria3.test
  mysql-test/suite/maria/t/maria_notembedded.test
  mysql-test/suite/ndb/r/ndb_alter_table.result
  mysql-test/suite/ndb/r/ndb_alter_table3.result
  mysql-test/suite/ndb/r/ndb_alter_table_backup.result
  mysql-test/suite/ndb/r/ndb_alter_table_online.result
  mysql-test/suite/ndb/r/ndb_alter_table_online2.result
  mysql-test/suite/ndb/r/ndb_basic.result
  mysql-test/suite/ndb/r/ndb_blob.result
  mysql-test/suite/ndb/r/ndb_cache.result
  mysql-test/suite/ndb/r/ndb_condition_pushdown.result
  mysql-test/suite/ndb/r/ndb_dd_ddl.result
  mysql-test/suite/ndb/r/ndb_insert.result
  mysql-test/suite/ndb/r/ndb_multi_row.result
  mysql-test/suite/ndb/r/ndb_partition_range.result
  mysql-test/suite/ndb/r/ndb_read_multi_range.result
  mysql-test/suite/ndb/r/ndb_replace.result
  mysql-test/suite/ndb/r/ndb_restore.result
  mysql-test/suite/ndb/r/ndb_restore_compat.result
  mysql-test/suite/ndb/r/ndb_restore_different_endian_data.result
  mysql-test/suite/ndb/r/ndb_single_user.result
  mysql-test/suite/ndb/r/ndb_trigger.result
  mysql-test/suite/ndb/t/disabled.def
  mysql-test/suite/ndb/t/ndb_alter_table.test
  mysql-test/suite/ndb/t/ndb_alter_table3.test
  mysql-test/suite/ndb/t/ndb_alter_table_backup.test
  mysql-test/suite/ndb/t/ndb_alter_table_online.test
  mysql-test/suite/ndb/t/ndb_alter_table_online2.test
  mysql-test/suite/ndb/t/ndb_basic.test
  mysql-test/suite/ndb/t/ndb_blob.test
  mysql-test/suite/ndb/t/ndb_cache.test
  mysql-test/suite/ndb/t/ndb_cache2.test
  mysql-test/suite/ndb/t/ndb_condition_pushdown.test
  mysql-test/suite/ndb/t/ndb_dd_ddl.test
  mysql-test/suite/ndb/t/ndb_dd_dump.test
  mysql-test/suite/ndb/t/ndb_insert.test
  mysql-test/suite/ndb/t/ndb_partition_range.test
  mysql-test/suite/ndb/t/ndb_read_multi_range.test
  mysql-test/suite/ndb/t/ndb_replace.test
  mysql-test/suite/ndb/t/ndb_restore.test
  mysql-test/suite/ndb/t/ndb_restore_compat.test
  mysql-test/suite/ndb/t/ndb_restore_different_endian_data.test
  mysql-test/suite/ndb/t/ndb_single_user.test
  mysql-test/suite/ndb/t/ndb_trigger.test
  mysql-test/suite/ndb_team/r/ndb_autodiscover3.result
  mysql-test/suite/ndb_team/t/ndb_autodiscover3.test
  mysql-test/suite/ndb_team/t/rpl_ndb_dd_advance.test
  mysql-test/suite/parts/r/partition_engine_ndb.result
  mysql-test/suite/rpl/r/rpl_heartbeat.result
  mysql-test/suite/rpl/r/rpl_locktrans_innodb.result
  mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result
  mysql-test/suite/rpl/r/rpl_truncate_2myisam.result
  mysql-test/suite/rpl/r/rpl_truncate_3innodb.result
  mysql-test/suite/rpl/t/disabled.def
  mysql-test/suite/rpl/t/rpl_rbr_to_sbr.test
  mysql-test/suite/rpl/t/rpl_row_basic_2myisam.test
  mysql-test/suite/rpl/t/rpl_row_basic_3innodb.test
  mysql-test/suite/rpl_ndb/r/rpl_ndb_basic.result
  mysql-test/suite/rpl_ndb/t/disabled.def
  mysql-test/suite/rpl_ndb/t/rpl_ndb_basic.test
  mysql-test/suite/rpl_ndb_big/r/rpl_ndb_apply_status.result
  mysql-test/suite/rpl_ndb_big/r/rpl_row_basic_7ndb.result
  mysql-test/suite/rpl_ndb_big/t/disabled.def
  mysql-test/suite/rpl_ndb_big/t/rpl_ndb_apply_status.test
  mysql-test/suite/rpl_ndb_big/t/rpl_row_basic_7ndb.test
  mysql-test/t/events_logs_tests-master.opt
  mysql-test/t/fulltext.test
  mysql-test/t/log_tables-big-master.opt
  mysql-test/t/log_tables-master.opt
  mysql-test/t/multi_statement-master.opt
  mysql-test/t/partition_not_windows.test
  mysql-test/t/ps-master.opt
  mysql-test/t/show_check-master.opt
  mysql-test/t/slow_query_log_file_basic-master.opt
  mysql-test/t/slow_query_log_file_func-master.opt
  mysql-test/t/sp-error.test
  mysql-test/t/status.test
  mysql-test/t/subselect3.test
  mysql-test/t/union-master.opt
  mysys/CMakeLists.txt
  mysys/Makefile.am
  mysys/hash.c
  mysys/lf_hash.c
  mysys/my_bitmap.c
  mysys/my_getopt.c
  mysys/my_init.c
  mysys/my_pthread.c
  mysys/my_sleep.c
  mysys/my_thr_init.c
  mysys/my_wincond.c
  mysys/my_winthread.c
  mysys/mysys_priv.h
  mysys/queues.c
  mysys/stacktrace.c
  mysys/thr_mutex.c
  mysys/waiting_threads.c
  netware/Makefile.am
  regex/CMakeLists.txt
  regex/Makefile.am
  scripts/CMakeLists.txt
  scripts/Makefile.am
  scripts/make_win_bin_dist
  sql/CMakeLists.txt
  sql/Makefile.am
  sql/backup/CMakeLists.txt
  sql/backup/backup_info.cc
  sql/backup/backup_info.h
  sql/backup/backup_kernel.h
  sql/backup/be_thread.cc
  sql/backup/data_backup.cc
  sql/backup/image_info.cc
  sql/backup/image_info.h
  sql/backup/kernel.cc
  sql/backup/logger.cc
  sql/backup/logger.h
  sql/backup/restore_info.h
  sql/backup/stream.cc
  sql/backup/stream.h
  sql/event_db_repository.cc
  sql/event_parse_data.cc
  sql/event_parse_data.h
  sql/event_queue.cc
  sql/event_scheduler.cc
  sql/events.cc
  sql/field.cc
  sql/field.h
  sql/gen_lex_hash.cc
  sql/ha_ndbcluster.cc
  sql/ha_ndbcluster.h
  sql/ha_ndbcluster_binlog.cc
  sql/ha_ndbcluster_binlog.h
  sql/ha_ndbcluster_cond.cc
  sql/ha_ndbcluster_cond.h
  sql/ha_ndbcluster_connection.cc
  sql/ha_ndbcluster_connection.h
  sql/ha_partition.cc
  sql/ha_partition.h
  sql/handler.cc
  sql/handler.h
  sql/item.cc
  sql/item.h
  sql/item_create.cc
  sql/item_func.cc
  sql/item_func.h
  sql/lock.cc
  sql/log.cc
  sql/log_event.cc
  sql/mysql_priv.h
  sql/mysqld.cc
  sql/opt_range.cc
  sql/partition_info.h
  sql/protocol.cc
  sql/rpl_injector.cc
  sql/rpl_injector.h
  sql/rpl_mi.cc
  sql/set_var.cc
  sql/share/errmsg.txt
  sql/si_logs.h
  sql/sp_cache.cc
  sql/sp_cache.h
  sql/sp_head.cc
  sql/sql_audit.cc
  sql/sql_base.cc
  sql/sql_cache.cc
  sql/sql_class.cc
  sql/sql_class.h
  sql/sql_connect.cc
  sql/sql_db.cc
  sql/sql_delete.cc
  sql/sql_insert.cc
  sql/sql_lex.cc
  sql/sql_lex.h
  sql/sql_parse.cc
  sql/sql_partition.cc
  sql/sql_rename.cc
  sql/sql_repl.cc
  sql/sql_select.cc
  sql/sql_select.h
  sql/sql_show.cc
  sql/sql_show.h
  sql/sql_table.cc
  sql/sql_union.cc
  sql/sql_update.cc
  sql/sql_yacc.yy
  sql/table.cc
  sql/table.h
  sql/udf_example.c
  storage/archive/Makefile.am
  storage/archive/archive_reader.c
  storage/blackhole/CMakeLists.txt
  storage/blackhole/ha_blackhole.cc
  storage/blackhole/ha_blackhole.h
  storage/csv/CMakeLists.txt
  storage/example/CMakeLists.txt
  storage/falcon/CompareAndSwapSparc.il
  storage/falcon/Configuration.cpp
  storage/falcon/DataPage.cpp
  storage/falcon/Database.cpp
  storage/falcon/IO.cpp
  storage/falcon/Index.cpp
  storage/falcon/IndexRootPage.cpp
  storage/falcon/IndexWalker.cpp
  storage/falcon/Interlock.h
  storage/falcon/Log.h
  storage/falcon/Makefile.am
  storage/falcon/MySQLCollation.cpp
  storage/falcon/PageInventoryPage.cpp
  storage/falcon/SRLBlobDelete.h
  storage/falcon/SRLBlobUpdate.h
  storage/falcon/SRLCreateIndex.h
  storage/falcon/SRLCreateSection.h
  storage/falcon/SRLCreateTableSpace.cpp
  storage/falcon/SRLCreateTableSpace.h
  storage/falcon/SRLData.h
  storage/falcon/SRLDelete.h
  storage/falcon/SRLDeleteIndex.cpp
  storage/falcon/SRLDeleteIndex.h
  storage/falcon/SRLDropTableSpace.cpp
  storage/falcon/SRLDropTableSpace.h
  storage/falcon/SRLFreePage.h
  storage/falcon/SRLIndexAdd.h
  storage/falcon/SRLIndexDelete.h
  storage/falcon/SRLIndexPage.h
  storage/falcon/SRLInversionPage.h
  storage/falcon/SRLOverflowPages.h
  storage/falcon/SRLRecordLocator.h
  storage/falcon/SRLRecordStub.h
  storage/falcon/SRLSectionLine.h
  storage/falcon/SRLSectionPage.h
  storage/falcon/SRLSectionPromotion.h
  storage/falcon/SRLSequencePage.h
  storage/falcon/SRLUpdateBlob.h
  storage/falcon/SRLUpdateIndex.h
  storage/falcon/SRLUpdateRecords.cpp
  storage/falcon/SRLUpdateRecords.h
  storage/falcon/SerialLog.cpp
  storage/falcon/SerialLog.h
  storage/falcon/SerialLogRecord.cpp
  storage/falcon/SerialLogRecord.h
  storage/falcon/StorageTable.cpp
  storage/falcon/StorageVersion.h
  storage/falcon/Table.cpp
  storage/falcon/Table.h
  storage/falcon/Transaction.cpp
  storage/falcon/TransformLib/StringTransform.cpp
  storage/falcon/Value.cpp
  storage/falcon/ha_falcon.cpp
  storage/falcon/ha_falcon.h
  storage/falcon/plug.in
  storage/heap/CMakeLists.txt
  storage/heap/Makefile.am
  storage/innobase/CMakeLists.txt
  storage/innobase/handler/ha_innodb.cc
  storage/innobase/handler/ha_innodb.h
  storage/maria/CMakeLists.txt
  storage/maria/KNOWN_BUGS.txt
  storage/maria/Makefile.am
  storage/maria/ha_maria.cc
  storage/maria/ha_maria.h
  storage/maria/ma_bitmap.c
  storage/maria/ma_blockrec.c
  storage/maria/ma_blockrec.h
  storage/maria/ma_checkpoint.c
  storage/maria/ma_close.c
  storage/maria/ma_commit.c
  storage/maria/ma_control_file.c
  storage/maria/ma_delete.c
  storage/maria/ma_extra.c
  storage/maria/ma_key.c
  storage/maria/ma_loghandler.c
  storage/maria/ma_open.c
  storage/maria/ma_pagecache.c
  storage/maria/ma_recovery.c
  storage/maria/ma_rkey.c
  storage/maria/ma_rnext.c
  storage/maria/ma_rnext_same.c
  storage/maria/ma_state.c
  storage/maria/ma_state.h
  storage/maria/ma_test1.c
  storage/maria/ma_test2.c
  storage/maria/ma_update.c
  storage/maria/ma_write.c
  storage/maria/maria_def.h
  storage/maria/trnman.c
  storage/maria/trnman_public.h
  storage/maria/unittest/CMakeLists.txt
  storage/maria/unittest/Makefile.am
  storage/myisam/CMakeLists.txt
  storage/myisam/Makefile.am
  storage/myisam/ha_myisam.cc
  storage/myisam/ha_myisam.h
  storage/myisam/mi_open.c
  storage/myisam/myisampack.c
  storage/myisammrg/CMakeLists.txt
  storage/myisammrg/ha_myisammrg.cc
  storage/ndb/Makefile.am
  storage/ndb/config/common.mk.am
  storage/ndb/config/type_ndbapitest.mk.am
  storage/ndb/config/type_ndbapitools.mk.am
  storage/ndb/docs/doxygen/postdoxy.pl
  storage/ndb/include/debugger/SignalLoggerManager.hpp
  storage/ndb/include/kernel/Interpreter.hpp
  storage/ndb/include/kernel/NodeState.hpp
  storage/ndb/include/kernel/signaldata/AttrInfo.hpp
  storage/ndb/include/kernel/signaldata/DictLock.hpp
  storage/ndb/include/kernel/signaldata/DumpStateOrd.hpp
  storage/ndb/include/kernel/signaldata/KeyInfo.hpp
  storage/ndb/include/kernel/signaldata/ListTables.hpp
  storage/ndb/include/kernel/signaldata/SumaImpl.hpp
  storage/ndb/include/logger/LogHandler.hpp
  storage/ndb/include/logger/Logger.hpp
  storage/ndb/include/mgmapi/mgmapi.h
  storage/ndb/include/mgmapi/mgmapi_config_parameters.h
  storage/ndb/include/mgmapi/mgmapi_debug.h
  storage/ndb/include/mgmapi/mgmapi_error.h
  storage/ndb/include/mgmapi/ndb_logevent.h
  storage/ndb/include/ndb_constants.h
  storage/ndb/include/ndb_version.h.in
  storage/ndb/include/ndbapi/Ndb.hpp
  storage/ndb/include/ndbapi/NdbApi.hpp
  storage/ndb/include/ndbapi/NdbBlob.hpp
  storage/ndb/include/ndbapi/NdbDictionary.hpp
  storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp
  storage/ndb/include/ndbapi/NdbIndexStat.hpp
  storage/ndb/include/ndbapi/NdbInterpretedCode.hpp
  storage/ndb/include/ndbapi/NdbOperation.hpp
  storage/ndb/include/ndbapi/NdbRecAttr.hpp
  storage/ndb/include/ndbapi/NdbReceiver.hpp
  storage/ndb/include/ndbapi/NdbScanFilter.hpp
  storage/ndb/include/ndbapi/NdbScanOperation.hpp
  storage/ndb/include/ndbapi/NdbTransaction.hpp
  storage/ndb/include/util/BaseString.hpp
  storage/ndb/include/util/InputStream.hpp
  storage/ndb/include/util/NdbOut.hpp
  storage/ndb/include/util/OutputStream.hpp
  storage/ndb/include/util/SimpleProperties.hpp
  storage/ndb/include/util/SocketServer.hpp
  storage/ndb/include/util/basestring_vsnprintf.h
  storage/ndb/include/util/ndb_opts.h
  storage/ndb/include/util/socket_io.h
  storage/ndb/ndbapi-examples/Makefile
  storage/ndb/ndbapi-examples/mgmapi_logevent/Makefile
  storage/ndb/ndbapi-examples/mgmapi_logevent2/Makefile
  storage/ndb/ndbapi-examples/ndbapi_async/Makefile
  storage/ndb/ndbapi-examples/ndbapi_async1/Makefile
  storage/ndb/ndbapi-examples/ndbapi_blob/Makefile
  storage/ndb/ndbapi-examples/ndbapi_blob_ndbrecord/Makefile
  storage/ndb/ndbapi-examples/ndbapi_blob_ndbrecord/main.cpp
  storage/ndb/ndbapi-examples/ndbapi_event/Makefile
  storage/ndb/ndbapi-examples/ndbapi_retries/Makefile
  storage/ndb/ndbapi-examples/ndbapi_s_i_ndbrecord/Makefile
  storage/ndb/ndbapi-examples/ndbapi_s_i_ndbrecord/main.cpp
  storage/ndb/ndbapi-examples/ndbapi_scan/Makefile
  storage/ndb/ndbapi-examples/ndbapi_simple/Makefile
  storage/ndb/ndbapi-examples/ndbapi_simple_dual/Makefile
  storage/ndb/ndbapi-examples/ndbapi_simple_index/Makefile
  storage/ndb/src/Makefile.am
  storage/ndb/src/common/debugger/EventLogger.cpp
  storage/ndb/src/common/debugger/signaldata/SignalNames.cpp
  storage/ndb/src/common/logger/LogHandler.cpp
  storage/ndb/src/common/logger/Logger.cpp
  storage/ndb/src/common/portlib/NdbCondition.c
  storage/ndb/src/common/portlib/NdbTick.c
  storage/ndb/src/common/transporter/TCP_Transporter.cpp
  storage/ndb/src/common/transporter/Transporter.cpp
  storage/ndb/src/common/transporter/TransporterRegistry.cpp
  storage/ndb/src/common/util/BaseString.cpp
  storage/ndb/src/common/util/Makefile.am
  storage/ndb/src/common/util/OutputStream.cpp
  storage/ndb/src/common/util/SocketServer.cpp
  storage/ndb/src/common/util/socket_io.cpp
  storage/ndb/src/common/util/version.c
  storage/ndb/src/cw/cpcd/APIService.cpp
  storage/ndb/src/cw/cpcd/Makefile.am
  storage/ndb/src/cw/cpcd/Process.cpp
  storage/ndb/src/cw/cpcd/main.cpp
  storage/ndb/src/kernel/Makefile.am
  storage/ndb/src/kernel/blocks/ERROR_codes.txt
  storage/ndb/src/kernel/blocks/Makefile.am
  storage/ndb/src/kernel/blocks/backup/Backup.cpp
  storage/ndb/src/kernel/blocks/backup/Makefile.am
  storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
  storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp
  storage/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp
  storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
  storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
  storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
  storage/ndb/src/kernel/blocks/dbdict/Makefile.am
  storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp
  storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
  storage/ndb/src/kernel/blocks/dbdih/Makefile.am
  storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
  storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp
  storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
  storage/ndb/src/kernel/blocks/dblqh/Makefile.am
  storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
  storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp
  storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
  storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
  storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp
  storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp
  storage/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp
  storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
  storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp
  storage/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp
  storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp
  storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp
  storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp
  storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp
  storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp
  storage/ndb/src/kernel/blocks/dbtup/Makefile.am
  storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.cpp
  storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.hpp
  storage/ndb/src/kernel/blocks/dbtux/Dbtux.hpp
  storage/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp
  storage/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp
  storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
  storage/ndb/src/kernel/blocks/lgman.cpp
  storage/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp
  storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
  storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp
  storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp
  storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
  storage/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp
  storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
  storage/ndb/src/kernel/blocks/restore.cpp
  storage/ndb/src/kernel/blocks/suma/Suma.cpp
  storage/ndb/src/kernel/blocks/suma/Suma.hpp
  storage/ndb/src/kernel/blocks/suma/SumaInit.cpp
  storage/ndb/src/kernel/blocks/trix/Trix.cpp
  storage/ndb/src/kernel/blocks/trix/Trix.hpp
  storage/ndb/src/kernel/blocks/tsman.cpp
  storage/ndb/src/kernel/error/ErrorReporter.cpp
  storage/ndb/src/kernel/main.cpp
  storage/ndb/src/kernel/vm/Configuration.cpp
  storage/ndb/src/kernel/vm/Emulator.cpp
  storage/ndb/src/kernel/vm/LongSignal.hpp
  storage/ndb/src/kernel/vm/Makefile.am
  storage/ndb/src/kernel/vm/RequestTracker.hpp
  storage/ndb/src/kernel/vm/SafeCounter.cpp
  storage/ndb/src/kernel/vm/SafeCounter.hpp
  storage/ndb/src/kernel/vm/SimplePropertiesSection.cpp
  storage/ndb/src/kernel/vm/SimulatedBlock.cpp
  storage/ndb/src/kernel/vm/SimulatedBlock.hpp
  storage/ndb/src/kernel/vm/TransporterCallback.cpp
  storage/ndb/src/kernel/vm/WatchDog.cpp
  storage/ndb/src/kernel/vm/bench_pool.cpp
  storage/ndb/src/kernel/vm/ndbd_malloc_impl.cpp
  storage/ndb/src/kernel/vm/pc.hpp
  storage/ndb/src/mgmapi/LocalConfig.cpp
  storage/ndb/src/mgmapi/mgmapi.cpp
  storage/ndb/src/mgmclient/CommandInterpreter.cpp
  storage/ndb/src/mgmclient/Makefile.am
  storage/ndb/src/mgmsrv/ConfigInfo.cpp
  storage/ndb/src/mgmsrv/InitConfigFileParser.cpp
  storage/ndb/src/mgmsrv/Makefile.am
  storage/ndb/src/mgmsrv/MgmtSrvr.cpp
  storage/ndb/src/mgmsrv/MgmtSrvr.hpp
  storage/ndb/src/mgmsrv/Services.cpp
  storage/ndb/src/mgmsrv/main.cpp
  storage/ndb/src/ndbapi/ClusterMgr.cpp
  storage/ndb/src/ndbapi/DictCache.cpp
  storage/ndb/src/ndbapi/DictCache.hpp
  storage/ndb/src/ndbapi/Makefile.am
  storage/ndb/src/ndbapi/Ndb.cpp
  storage/ndb/src/ndbapi/NdbApiSignal.hpp
  storage/ndb/src/ndbapi/NdbBlob.cpp
  storage/ndb/src/ndbapi/NdbDictionary.cpp
  storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp
  storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp
  storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp
  storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp
  storage/ndb/src/ndbapi/NdbIndexStat.cpp
  storage/ndb/src/ndbapi/NdbInterpretedCode.cpp
  storage/ndb/src/ndbapi/NdbOperation.cpp
  storage/ndb/src/ndbapi/NdbOperationDefine.cpp
  storage/ndb/src/ndbapi/NdbOperationExec.cpp
  storage/ndb/src/ndbapi/NdbOperationInt.cpp
  storage/ndb/src/ndbapi/NdbOperationSearch.cpp
  storage/ndb/src/ndbapi/NdbRecAttr.cpp
  storage/ndb/src/ndbapi/NdbReceiver.cpp
  storage/ndb/src/ndbapi/NdbRecord.hpp
  storage/ndb/src/ndbapi/NdbScanFilter.cpp
  storage/ndb/src/ndbapi/NdbScanOperation.cpp
  storage/ndb/src/ndbapi/NdbTransaction.cpp
  storage/ndb/src/ndbapi/Ndbif.cpp
  storage/ndb/src/ndbapi/Ndbinit.cpp
  storage/ndb/src/ndbapi/ObjectMap.cpp
  storage/ndb/src/ndbapi/ObjectMap.hpp
  storage/ndb/src/ndbapi/TransporterFacade.cpp
  storage/ndb/src/ndbapi/TransporterFacade.hpp
  storage/ndb/src/ndbapi/ndb_cluster_connection.cpp
  storage/ndb/src/ndbapi/ndberror.c
  storage/ndb/test/include/AtrtClient.hpp
  storage/ndb/test/include/DbUtil.hpp
  storage/ndb/test/include/HugoAsynchTransactions.hpp
  storage/ndb/test/include/HugoOperations.hpp
  storage/ndb/test/include/HugoTransactions.hpp
  storage/ndb/test/include/NDBT_Test.hpp
  storage/ndb/test/include/NdbRestarter.hpp
  storage/ndb/test/ndbapi/Makefile.am
  storage/ndb/test/ndbapi/ScanFilter.hpp
  storage/ndb/test/ndbapi/ScanFunctions.hpp
  storage/ndb/test/ndbapi/ScanInterpretTest.hpp
  storage/ndb/test/ndbapi/acrt/NdbRepStress.cpp
  storage/ndb/test/ndbapi/bank/Bank.cpp
  storage/ndb/test/ndbapi/bank/BankLoad.cpp
  storage/ndb/test/ndbapi/bench/mainAsyncGenerator.cpp
  storage/ndb/test/ndbapi/bench/ndb_async2.cpp
  storage/ndb/test/ndbapi/bench/testData.h
  storage/ndb/test/ndbapi/flexAsynch.cpp
  storage/ndb/test/ndbapi/flexBench.cpp
  storage/ndb/test/ndbapi/flexScan.cpp
  storage/ndb/test/ndbapi/msa.cpp
  storage/ndb/test/ndbapi/testBlobs.cpp
  storage/ndb/test/ndbapi/testDataBuffers.cpp
  storage/ndb/test/ndbapi/testDict.cpp
  storage/ndb/test/ndbapi/testIndex.cpp
  storage/ndb/test/ndbapi/testIndexStat.cpp
  storage/ndb/test/ndbapi/testInterpreter.cpp
  storage/ndb/test/ndbapi/testNDBT.cpp
  storage/ndb/test/ndbapi/testNdbApi.cpp
  storage/ndb/test/ndbapi/testNodeRestart.cpp
  storage/ndb/test/ndbapi/testOIBasic.cpp
  storage/ndb/test/ndbapi/testOperations.cpp
  storage/ndb/test/ndbapi/testPartitioning.cpp
  storage/ndb/test/ndbapi/testSRBank.cpp
  storage/ndb/test/ndbapi/testScan.cpp
  storage/ndb/test/ndbapi/testScanFilter.cpp
  storage/ndb/test/ndbapi/testScanPerf.cpp
  storage/ndb/test/ndbapi/testSystemRestart.cpp
  storage/ndb/test/ndbapi/testTransactions.cpp
  storage/ndb/test/ndbapi/test_event.cpp
  storage/ndb/test/run-test/Makefile.am
  storage/ndb/test/run-test/atrt-analyze-result.sh
  storage/ndb/test/run-test/atrt.hpp
  storage/ndb/test/run-test/autotest-boot.sh
  storage/ndb/test/run-test/autotest-run.sh
  storage/ndb/test/run-test/daily-basic-tests.txt
  storage/ndb/test/run-test/daily-devel-tests.txt
  storage/ndb/test/run-test/files.cpp
  storage/ndb/test/run-test/main.cpp
  storage/ndb/test/run-test/setup.cpp
  storage/ndb/test/run-test/test-tests.txt
  storage/ndb/test/src/AtrtClient.cpp
  storage/ndb/test/src/CpcClient.cpp
  storage/ndb/test/src/DbUtil.cpp
  storage/ndb/test/src/HugoAsynchTransactions.cpp
  storage/ndb/test/src/HugoOperations.cpp
  storage/ndb/test/src/HugoTransactions.cpp
  storage/ndb/test/src/NDBT_Tables.cpp
  storage/ndb/test/src/NDBT_Test.cpp
  storage/ndb/test/src/NdbBackup.cpp
  storage/ndb/test/src/NdbRestarter.cpp
  storage/ndb/test/src/UtilTransactions.cpp
  storage/ndb/test/tools/connect.cpp
  storage/ndb/test/tools/hugoPkRead.cpp
  storage/ndb/test/tools/rep_latency.cpp
  storage/ndb/tools/desc.cpp
  storage/ndb/tools/ndb_size.pl
  storage/ndb/tools/restore/Restore.cpp
  storage/ndb/tools/restore/consumer_restore.cpp
  storage/ndb/tools/restore/restore_main.cpp
  storage/ndb/tools/select_all.cpp
  storage/ndb/tools/select_count.cpp
  storage/ndb/tools/waiter.cpp
  strings/CMakeLists.txt
  strings/Makefile.am
  strings/conf_to_src.c
  support-files/build-tags
  support-files/compiler_warnings.supp
  support-files/mysql.spec.sh
  tests/CMakeLists.txt
  unittest/examples/CMakeLists.txt
  unittest/mysys/CMakeLists.txt
  unittest/mysys/Makefile.am
  unittest/mytap/CMakeLists.txt
  vio/CMakeLists.txt
  zlib/CMakeLists.txt
  mysql-test/r/slave_allow_batching_basic.result
  mysql-test/suite/ndb_binlog/r/ndb_binlog_basic.result
  mysql-test/suite/ndb_binlog/r/ndb_binlog_ddl_multi.result
  mysql-test/suite/ndb_binlog/r/ndb_binlog_log_bin.result
  mysql-test/suite/ndb_binlog/t/ndb_binlog_basic.test
  mysql-test/suite/ndb_binlog/r/ndb_binlog_format.result
  mysql-test/t/slave_allow_batching_basic.test
  storage/ndb/src/common/util/ndb_init.cpp

=== modified file 'BUILD/compile-dist'
--- a/BUILD/compile-dist	2008-11-22 15:24:06 +0000
+++ b/BUILD/compile-dist	2008-12-29 12:05:15 +0000
@@ -11,16 +11,33 @@ test -f Makefile && make maintainer-clea
 path=`dirname $0`
 . $path/autorun.sh
 
+gmake=
+for x in gmake gnumake make; do
+  if $x --version 2>/dev/null | grep GNU > /dev/null; then
+    gmake=$x
+    break;
+  fi
+done
+
+if [ -z "$gmake" ]; then
+  # Our build may not depend on GNU make, but I wouldn't count on it
+  echo "Please install GNU make, and ensure it is in your path as gnumake, gmake, or make" >&2
+  exit 2
+fi
+
 # Default to gcc for CC and CXX
 if test -z "$CXX" ; then
+  export CXX
   CXX=gcc
   # Set some required compile options
   if test -z "$CXXFLAGS" ; then
+    export CXXFLAGS
     CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti"
   fi
 fi
 
 if test -z "$CC" ; then
+  export CC
   CC=gcc
 fi
 
@@ -28,32 +45,18 @@ fi
 # Use ccache, if available
 if ccache -V > /dev/null 2>&1
 then
-  if echo "$CC" | grep "ccache" > /dev/null
+  if echo "$CC" | grep -v ccache > /dev/null
   then
-    :
-  else
+    export CC
     CC="ccache $CC"
   fi
-  if echo "$CXX" | grep "ccache" > /dev/null
+  if echo "$CXX" | grep -v ccache > /dev/null
   then
-    :
-  else
+    export CXX
     CXX="ccache $CXX"
   fi
 fi
 
-if test -z "$MAKE"
-then
-  if gmake -v > /dev/null 2>&1
-  then
-    MAKE="gmake"
-  else
-    MAKE="make"
-  fi
-fi
-
-export CC CXX MAKE
-
 # Make sure to enable all features that affect "make dist"
 # Remember that configure restricts the man pages to the configured features !
 ./configure \
@@ -61,5 +64,5 @@ export CC CXX MAKE
   --with-embedded-server \
   --with-falcon \
   --with-ndbcluster
-$MAKE
+$gmake
 

=== modified file 'BUILD/compile-pentium-gcov'
--- a/BUILD/compile-pentium-gcov	2007-08-22 18:02:23 +0000
+++ b/BUILD/compile-pentium-gcov	2008-12-31 13:18:04 +0000
@@ -7,7 +7,7 @@ CCACHE_GCOV_VERSION_ENABLED=0
 if ccache -V > /dev/null 2>&1
 then
   CCACHE_VER=`ccache -V | head -1 | sed s/"ccache version "//`
-  if test "$CCACHE_VER" == "2.4-gcov"
+  if test "$CCACHE_VER" = "2.4-gcov"
   then
     CCACHE_GCOV_VERSION_ENABLED=1
   else
@@ -20,7 +20,8 @@ export CCACHE_GCOV_VERSION_ENABLED
 path=`dirname $0`
 . "$path/SETUP.sh"
 
-export LDFLAGS="$gcov_link_flags"
+LDFLAGS="$gcov_link_flags"
+export LDFLAGS
 
 extra_flags="$pentium_cflags $debug_cflags $max_cflags $gcov_compile_flags"
 c_warnings="$c_warnings $debug_extra_warnings"

=== modified file 'BUILD/compile-solaris-amd64'
--- a/BUILD/compile-solaris-amd64	2007-04-12 11:20:38 +0000
+++ b/BUILD/compile-solaris-amd64	2008-12-31 13:18:04 +0000
@@ -1,16 +1,18 @@
-#!/usr/bin/bash
+#!/bin/sh
 
-function _find_mysql_root () (
+_find_mysql_root ()
+{
+  (
     while [ "x$PWD" != "x/" ]; do
 	# Check if some directories are present
 	if [ -d BUILD -a -d sql -a -d mysys ]; then
 	    echo "$PWD"
-	    return 0
+            break
 	fi
 	cd ..
     done
-    return 1
 )
+}
 
 make -k clean || true
 /bin/rm -f */.deps/*.P config.cache
@@ -28,7 +30,7 @@ CFLAGS="$warning_flags $compiler_flags"
 CXXFLAGS="" 
 LDFLAGS="-O3 -g -static-libgcc"
 LIBS=-lmtmalloc
-root=$(_find_mysql_root)
+root=`_find_mysql_root`
 
 $root/configure \
     --prefix=/usr/local/mysql \

=== modified file 'Makefile.am'
--- a/Makefile.am	2008-12-13 11:02:16 +0000
+++ b/Makefile.am	2008-12-17 18:40:14 +0000
@@ -178,8 +178,8 @@ test-bt:
 	fi
 	-if [ -d mysql-test/suite/nist ] ; then \
 	  cd mysql-test ; MTR_BUILD_THREAD=auto \
+	      @PERL@ ./mysql-test-run.pl --comment=NIST+normal --force --suite=nist ; \
 	      @PERL@ ./mysql-test-run.pl --comment=NIST+ps --force --suite=nist --ps-protocol ; \
-	      @PERL@ ./mysql-test-run.pl --comment=nist+ps --force --suite=nist --ps-protocol ; \
 	fi
 	-if [ -e bin/mysqltest_embedded -o -e libmysqld/examples/mysqltest_embedded ] ; then \
 	  cd mysql-test ; MTR_BUILD_THREAD=auto \

=== added file 'config/ac-macros/libmemcached.m4'
--- a/config/ac-macros/libmemcached.m4	1970-01-01 00:00:00 +0000
+++ b/config/ac-macros/libmemcached.m4	2008-12-20 01:41:31 +0000
@@ -0,0 +1,29 @@
+dnl
+dnl Copyright (C) 2008 Sun Microsystems
+dnl 
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; version 2 of the License.
+dnl 
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl 
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+dnl
+dnl Check to find libmemcached.
+
+AC_DEFUN([_SEARCH_FOR_LIBMEMCACHED],[
+  SEARCH_FOR_LIB(memcached,memcached_create,[libmemcached/memcached.h])
+  AM_CONDITIONAL([BUILD_MEMCACHED],[test "$ac_cv_have_memcached" = "yes"])
+])
+
+dnl Split this into a _hidden function and a public with a require. This way
+dnl any number of plugins can call the code and the real guts only get 
+dnl called once.
+AC_DEFUN([WITH_LIBMEMCACHED],[
+  AC_REQUIRE([_SEARCH_FOR_LIBMEMCACHED])
+])

=== added file 'config/ac-macros/search_for_lib.m4'
--- a/config/ac-macros/search_for_lib.m4	1970-01-01 00:00:00 +0000
+++ b/config/ac-macros/search_for_lib.m4	2008-12-20 01:41:31 +0000
@@ -0,0 +1,107 @@
+dnl
+dnl Copyright (C) 2008 Sun Microsystems
+dnl 
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; version 2 of the License.
+dnl 
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl 
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+dnl
+dnl Contributed with Love by Drizzle. If you make any modifications, they'd
+dnl love to know about them.
+dnl
+dnl SEARCH_FOR_LIB(LIB, FUNCTIONS, FUNCTION,
+dnl                [ACTION-IF-NOT-FOUND],
+dnl                [LIBS_TO_ADD])
+
+AC_DEFUN([SEARCH_FOR_LIB],
+[
+  AS_VAR_PUSHDEF([with_lib], [with_$1])
+  AS_VAR_PUSHDEF([ac_header], [ac_cv_header_$3])
+  AS_VAR_PUSHDEF([have_lib], [ac_cv_have_$1])
+  AS_VAR_PUSHDEF([libs_var], AS_TR_CPP([$1_LIBS]))
+  AS_VAR_PUSHDEF([cflags_var], AS_TR_CPP([$1_CFLAGS]))
+  AS_VAR_PUSHDEF([path_var], AS_TR_CPP([$1_PATH]))
+  AS_LITERAL_IF([$1],
+                [AS_VAR_PUSHDEF([ac_lib], [ac_cv_lib_$1_$2])],
+                [AS_VAR_PUSHDEF([ac_lib], [ac_cv_lib_$1''_$2])])
+
+  AS_IF([test "x$prefix" = "xNONE"],
+    [AS_VAR_SET([path_var],["$ac_default_prefix"])],
+    [AS_VAR_SET([path_var],["$prefix"])])
+
+
+  AC_ARG_WITH([$1],
+    [AS_HELP_STRING([--with-$1@<:@=DIR@:>@],
+       [Use lib$1 in DIR])],
+    [ AS_VAR_SET([with_lib], [$withval]) ],
+    [ AS_VAR_SET([with_lib], [yes]) ])
+
+  AS_IF([test AS_VAR_GET([with_lib]) = yes],[
+    AC_CHECK_HEADERS([$3])
+
+    my_save_LIBS="$LIBS"
+    LIBS="$5"
+    AC_CHECK_LIB($1, $2)
+    AS_VAR_SET([libs_var],[${LIBS}])
+    LIBS="${my_save_LIBS}"
+    AS_VAR_SET([cflags_var],[""])
+    AS_IF([test AS_VAR_GET([ac_header]) = "$3" -a AS_VAR_GET([ac_lib]) = yes],
+      [AS_VAR_SET([have_lib],[yes])
+       AS_VAR_SET([path_var],[$PATH])
+      ],
+      [AS_VAR_SET([have_lib],[no])
+       AS_VAR_SET([with_lib],["AS_VAR_GET([path_var]) /usr/local /opt/csw /opt/local"])
+      ])
+  ])
+  AS_IF([test "AS_VAR_GET([with_lib])" != yes],[
+   for libloc in AS_VAR_GET([with_lib])
+   do
+    AC_MSG_CHECKING(for $1 in $libloc)
+    if test -f $libloc/$3 -a -f $libloc/lib$1.a
+    then
+      owd=`pwd`
+      if cd $libloc; then libloc=`pwd`; cd $owd; fi
+      AS_VAR_SET([cflags_var],[-I$libloc])
+      AS_VAR_SET([libs_var],["-L$libloc -l$1"])
+      AS_VAR_SET([path_var],["$libloc:$PATH"])
+      AS_VAR_SET([have_lib],[yes])
+      AC_MSG_RESULT([yes])
+      break
+    elif test -f $libloc/include/$3 -a -f $libloc/lib/lib$1.a; then
+      owd=`pwd`
+      if cd $libloc; then libloc=`pwd`; cd $owd; fi
+      AS_VAR_SET([cflags_var],[-I$libloc/include])
+      AS_VAR_SET([libs_var],["-L$libloc/lib -l$1"])
+      AS_VAR_SET([path_var],["$libloc/bin:$PATH"])
+      AS_VAR_SET([have_lib],[yes])
+      AC_MSG_RESULT([yes])
+      break
+    else
+      AC_MSG_RESULT([no])
+      AS_VAR_SET([have_lib],[no])
+    fi
+   done
+  ])
+  AS_IF([test AS_VAR_GET([have_lib]) = no],[
+    AC_MSG_WARN([$3 or lib$1.a not found. Try installing $1 developement packages])
+    $4
+  ])
+  AC_SUBST(libs_var)
+  AC_SUBST(cflags_var)
+  AC_SUBST(path_var)
+  AS_VAR_POPDEF([with_lib])
+  AS_VAR_POPDEF([ac_header])
+  AS_VAR_POPDEF([libs_var])
+  AS_VAR_POPDEF([cflags_var])
+  AS_VAR_POPDEF([path_var])
+  AS_VAR_POPDEF([have_lib])
+  AS_VAR_POPDEF([ac_lib])
+])    

=== modified file 'configure.in'
--- a/configure.in	2008-12-17 13:06:53 +0000
+++ b/configure.in	2008-12-31 13:49:36 +0000
@@ -64,6 +64,8 @@ sinclude(config/ac-macros/readline.m4)
 sinclude(config/ac-macros/ssl.m4)
 sinclude(config/ac-macros/libevent.m4)
 sinclude(config/ac-macros/zlib.m4)
+sinclude(config/search_for_lib.m4)
+sinclude(config/libmemcached.m4)
 
 # Remember to add a directory sql/share/LANGUAGE
 AVAILABLE_LANGUAGES="\
@@ -403,7 +405,7 @@ fi
 MYSQL_PROG_AR
 
 # libmysqlclient versioning when linked with GNU ld.
-if $LD --version 2>/dev/null| grep GNU >/dev/null 2>&1; then
+if $LD --version 2>/dev/null | grep GNU >/dev/null 2>&1; then
   LD_VERSION_SCRIPT="-Wl,--version-script=\$(top_builddir)/libmysql/libmysql.ver"
   AC_CONFIG_FILES(libmysql/libmysql.ver)
 fi

=== modified file 'libmysqld/examples/test-run'
--- a/libmysqld/examples/test-run	2006-11-13 06:39:15 +0000
+++ b/libmysqld/examples/test-run	2008-12-31 13:18:04 +0000
@@ -1,4 +1,4 @@
-#! /bin/sh
+#!/bin/bash
 
 # This is slapped together as a quick way to run the tests and
 # is not meant for prime time.  Please hack at it and submit

=== modified file 'mysql-test/create-test-result'
--- a/mysql-test/create-test-result	2004-08-16 14:09:57 +0000
+++ b/mysql-test/create-test-result	2008-12-31 13:18:04 +0000
@@ -10,13 +10,13 @@ if [ -z "$EDITOR" ] ; then
  EDITOR=vi
 fi
 
-function die()
+die()
 {
   echo $1
   exit 1
 }
 
-function usage()
+usage()
 {
   echo "Usage: $0 test_name"
   exit 1

=== modified file 'mysql-test/mysql-test-run.pl'
--- a/mysql-test/mysql-test-run.pl	2008-12-14 11:36:15 +0000
+++ b/mysql-test/mysql-test-run.pl	2008-12-17 19:46:23 +0000
@@ -1473,16 +1473,22 @@ sub executable_setup_ndb () {
 				"$glob_basedir/storage/ndb",
 				"$glob_basedir/bin");
 
+  # Some might be found in sbin, not bin.
+  my $daemon_path= mtr_file_exists("$glob_basedir/ndb",
+				   "$glob_basedir/storage/ndb",
+				   "$glob_basedir/sbin",
+				   "$glob_basedir/bin");
+
   $exe_ndbd=
     mtr_exe_maybe_exists("$ndb_path/src/kernel/ndbd",
-			 "$ndb_path/ndbd",
+			 "$daemon_path/ndbd",
 			 "$glob_basedir/libexec/ndbd");
   $exe_ndb_mgm=
     mtr_exe_maybe_exists("$ndb_path/src/mgmclient/ndb_mgm",
 			 "$ndb_path/ndb_mgm");
   $exe_ndb_mgmd=
     mtr_exe_maybe_exists("$ndb_path/src/mgmsrv/ndb_mgmd",
-			 "$ndb_path/ndb_mgmd",
+			 "$daemon_path/ndb_mgmd",
 			 "$glob_basedir/libexec/ndb_mgmd");
   $exe_ndb_waiter=
     mtr_exe_maybe_exists("$ndb_path/tools/ndb_waiter",

=== modified file 'mysql-test/r/func_math.result'
--- a/mysql-test/r/func_math.result	2008-11-24 09:53:39 +0000
+++ b/mysql-test/r/func_math.result	2008-12-22 12:44:57 +0000
@@ -383,8 +383,10 @@ SELECT b DIV 900 y FROM t1 GROUP BY y;
 y
 0
 Warnings:
-Warning	1292	Truncated incorrect INTEGER value: 'str1'
-Warning	1292	Truncated incorrect INTEGER value: 'str2'
+Warning	1366	Incorrect decimal value: '' for column '' at row -1
+Warning	1292	Truncated incorrect DECIMAL value: 'str1'
+Warning	1366	Incorrect decimal value: '' for column '' at row -1
+Warning	1292	Truncated incorrect DECIMAL value: 'str2'
 SELECT c DIV 900 y FROM t1 GROUP BY y;
 y
 0
@@ -460,3 +462,8 @@ SELECT POW(10, 309);
 POW(10, 309)
 NULL
 End of 5.1 tests
+select 123456789012345678901234567890.123456789012345678901234567890 div 1 as x;
+ERROR 22003: Out of range value for column 'x' at row 1
+select "123456789012345678901234567890.123456789012345678901234567890" div 1 as x;
+ERROR 22003: Out of range value for column 'x' at row 1
+End of 6.0 tests

=== modified file 'mysql-test/r/group_by.result'
--- a/mysql-test/r/group_by.result	2008-11-06 18:39:27 +0000
+++ b/mysql-test/r/group_by.result	2008-11-26 13:04:00 +0000
@@ -1543,8 +1543,8 @@ id	select_type	table	type	possible_keys
 EXPLAIN SELECT 1 FROM t1 WHERE a IN
 (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2));
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	144	Start temporary
-1	PRIMARY	t1	eq_ref	PRIMARY,i2	PRIMARY	4	test.t1.a	1	Using index; End temporary
+1	PRIMARY	t1	index	PRIMARY,i2	PRIMARY	4	NULL	144	Using index
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	144	Using where; FirstMatch(t1)
 CREATE TABLE t2 (a INT, b INT, KEY(a));
 INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4);
 EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2;
@@ -1556,8 +1556,8 @@ id	select_type	table	type	possible_keys
 EXPLAIN SELECT 1 FROM t2 WHERE a IN
 (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2));
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	144	Start temporary
-1	PRIMARY	t2	index	a	a	5	NULL	4	Using where; Using index; End temporary; Using join buffer
+1	PRIMARY	t2	index	a	a	5	NULL	4	Using index
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	144	Using where; FirstMatch(t2)
 SHOW VARIABLES LIKE 'old';
 Variable_name	Value
 old	OFF

=== added file 'mysql-test/r/innodb_bug34053.result'
--- a/mysql-test/r/innodb_bug34053.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/innodb_bug34053.result	2008-09-15 21:33:05 +0000
@@ -0,0 +1 @@
+SET storage_engine=InnoDB;

=== modified file 'mysql-test/r/subselect.result'
--- a/mysql-test/r/subselect.result	2008-12-14 11:36:15 +0000
+++ b/mysql-test/r/subselect.result	2008-12-22 20:00:22 +0000
@@ -1356,11 +1356,11 @@ a
 3
 explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	PRIMARY	t2	index	a	a	5	NULL	4	100.00	Using index; Start temporary
-1	PRIMARY	t1	ref	a	a	5	test.t2.a	101	100.00	Using index
-1	PRIMARY	t3	index	a	a	5	NULL	3	100.00	Using where; Using index; End temporary; Using join buffer
+1	PRIMARY	t2	index	a	a	5	NULL	4	100.00	Using index
+1	PRIMARY	t3	index	a	a	5	NULL	3	100.00	Using index
+1	PRIMARY	t1	ref	a	a	10	test.t2.a,test.t3.a	116	100.00	Using index; FirstMatch(t2)
 Warnings:
-Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1` join `test`.`t3`) where ((`test`.`t1`.`a` = `test`.`t2`.`a`) and (`test`.`t3`.`a` = `test`.`t1`.`b`))
+Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1` join `test`.`t3`) where ((`test`.`t1`.`a` = `test`.`t2`.`a`) and (`test`.`t1`.`b` = `test`.`t3`.`a`))
 insert into t1 values (3,31);
 select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
 a
@@ -2818,8 +2818,8 @@ Warnings:
 Note	1003	select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<in_optimizer>((`test`.`t1`.`one`,`test`.`t1`.`two`),<exists>(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where ((`test`.`t2`.`flag` = '0') and trigcond(((<cache>(`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond(((<cache>(`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`)))) having (trigcond(<is_not_null_test>(`test`.`t2`.`one`)) and trigcond(<is_not_null_test>(`test`.`t2`.`two`))))) AS `test` from `test`.`t1`
 explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N');
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	8	100.00	Start temporary
-1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	9	100.00	Using where; End temporary; Using join buffer
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	8	100.00	
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	9	100.00	Using where; FirstMatch(t1)
 Warnings:
 Note	1003	select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`two` = `test`.`t1`.`two`) and (`test`.`t2`.`one` = `test`.`t1`.`one`) and (`test`.`t2`.`flag` = 'N'))
 explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1;
@@ -4367,13 +4367,13 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where
 2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using temporary; Using filesort
 Warnings:
-Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,1 in ( <materialize> (select 1 AS `1` from `test`.`t1` group by `test`.`t1`.`a` ), <primary_index_lookup>(1 in <temporary table> on distinct_key)))
+Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,1 in ( <materialize> (select 1 AS `1` from `test`.`t1` group by `test`.`t1`.`a` ), <primary_index_lookup>(1 in <temporary table> on distinct_key where ((1 = `materialized subselect`.`1`)))))
 EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where
 2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where; Using temporary; Using filesort
 Warnings:
-Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,1 in ( <materialize> (select 1 AS `1` from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` ), <primary_index_lookup>(1 in <temporary table> on distinct_key)))
+Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,1 in ( <materialize> (select 1 AS `1` from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` ), <primary_index_lookup>(1 in <temporary table> on distinct_key where ((1 = `materialized subselect`.`1`)))))
 DROP TABLE t1;
 End of 5.0 tests.
 create table t_out (subcase char(3),

=== modified file 'mysql-test/r/subselect2.result'
--- a/mysql-test/r/subselect2.result	2008-05-01 22:41:35 +0000
+++ b/mysql-test/r/subselect2.result	2008-07-27 19:17:41 +0000
@@ -123,16 +123,16 @@ DOCID	DOCNAME	DOCTYPEID	FOLDERID	AUTHOR
 c373e9f5ad07993f3859444553544200	Last Discussion	c373e9f5ad079174ff17444553544200	c373e9f5ad0796c0eca4444553544200	Goldilocks	2003-06-09 11:21:06	Title: Last Discussion	NULL	Setting new abstract and keeping doc checked out	2003-06-09 10:51:26	2003-06-09 10:51:26	NULL	NULL	NULL	03eea05112b845949f3fd03278b5fe43	2003-06-09 11:21:06	admin	0	NULL	Discussion	NULL	NULL
 EXPLAIN EXTENDED SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JOIN t4 ON t2.DOCTYPEID = t4.DOCTYPEID LEFT OUTER JOIN t1 ON t2.DOCID = t1.DOCID WHERE t2.FOLDERID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID IN(SELECT t3.FOLDERID FROM t3 WHERE t3.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t3.FOLDERNAME = 'Level1') AND t3.FOLDERNAME = 'Level2') AND t3.FOLDERNAME = 'Level3') AND t3.FOLDERNAME = 'CopiedFolder') AND t3.FOLDERNAME = 'Movie Reviews') AND t2.DOCNAME = 'Last Discussion';
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	PRIMARY	t3	ref	PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX	CMFLDRPARNT_IDX	35	const	6	100.00	Using index condition; Using where
-1	PRIMARY	t3	ref	PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX	CMFLDRPARNT_IDX	35	test.t3.FOLDERID	1	100.00	Using where
-1	PRIMARY	t3	ref	PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX	CMFLDRPARNT_IDX	35	test.t3.FOLDERID	1	100.00	Using where
-1	PRIMARY	t3	ref	PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX	CMFLDRPARNT_IDX	35	test.t3.FOLDERID	1	100.00	Using where
-1	PRIMARY	t3	ref	PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX	CMFLDRPARNT_IDX	35	test.t3.FOLDERID	1	100.00	Using where
-1	PRIMARY	t2	ALL	DDOCTYPEID_IDX,DFOLDERID_IDX	NULL	NULL	NULL	9	77.78	Using where; Using join buffer
+1	PRIMARY	t2	ALL	DDOCTYPEID_IDX	NULL	NULL	NULL	9	100.00	Using where
 1	PRIMARY	t1	eq_ref	PRIMARY	PRIMARY	34	test.t2.DOCID	1	100.00	
 1	PRIMARY	t4	eq_ref	PRIMARY	PRIMARY	34	test.t2.DOCTYPEID	1	100.00	
+2	DEPENDENT SUBQUERY	t3	eq_ref	PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX	PRIMARY	34	func	1	100.00	Using where
+2	DEPENDENT SUBQUERY	t3	eq_ref	PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX	PRIMARY	34	test.t3.PARENTID	1	100.00	Using where
+2	DEPENDENT SUBQUERY	t3	eq_ref	PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX	PRIMARY	34	test.t3.PARENTID	1	100.00	Using where
+2	DEPENDENT SUBQUERY	t3	eq_ref	PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX	PRIMARY	34	test.t3.PARENTID	1	100.00	Using where
+2	DEPENDENT SUBQUERY	t3	eq_ref	PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX	PRIMARY	34	test.t3.PARENTID	1	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t2`.`DOCID` AS `DOCID`,`test`.`t2`.`DOCNAME` AS `DOCNAME`,`test`.`t2`.`DOCTYPEID` AS `DOCTYPEID`,`test`.`t2`.`FOLDERID` AS `FOLDERID`,`test`.`t2`.`AUTHOR` AS `AUTHOR`,`test`.`t2`.`CREATED` AS `CREATED`,`test`.`t2`.`TITLE` AS `TITLE`,`test`.`t2`.`SUBTITLE` AS `SUBTITLE`,`test`.`t2`.`DOCABSTRACT` AS `DOCABSTRACT`,`test`.`t2`.`PUBLISHDATE` AS `PUBLISHDATE`,`test`.`t2`.`EXPIRATIONDATE` AS `EXPIRATIONDATE`,`test`.`t2`.`LOCKEDBY` AS `LOCKEDBY`,`test`.`t2`.`STATUS` AS `STATUS`,`test`.`t2`.`PARENTDOCID` AS `PARENTDOCID`,`test`.`t2`.`REPID` AS `REPID`,`test`.`t2`.`MODIFIED` AS `MODIFIED`,`test`.`t2`.`MODIFIER` AS `MODIFIER`,`test`.`t2`.`PUBLISHSTATUS` AS `PUBLISHSTATUS`,`test`.`t2`.`ORIGINATOR` AS `ORIGINATOR`,`test`.`t4`.`DOCTYPENAME` AS `DOCTYPENAME`,`test`.`t1`.`CONTENTSIZE` AS `CONTENTSIZE`,`test`.`t1`.`MIMETYPE` AS `MIMETYPE` from `test`.`t3` join `test`.`t3` join `test`.`t3` join `test`.`t3` join `test`.`t3` join `test`.`t2` join `test`.`t4` left join `
 test`.`t1` on((`test`.`t1`.`DOCID` = `test`.`t2`.`DOCID`)) where ((`test`.`t4`.`DOCTYPEID` = `test`.`t2`.`DOCTYPEID`) and (`test`.`t2`.`FOLDERID` = `test`.`t3`.`FOLDERID`) and (`test`.`t3`.`PARENTID` = `test`.`t3`.`FOLDERID`) and (`test`.`t3`.`PARENTID` = `test`.`t3`.`FOLDERID`) and (`test`.`t3`.`PARENTID` = `test`.`t3`.`FOLDERID`) and (`test`.`t3`.`PARENTID` = `test`.`t3`.`FOLDERID`) and (`test`.`t3`.`FOLDERNAME` = 'Level1') and (`test`.`t3`.`PARENTID` = '2f6161e879db43c1a5b82c21ddc49089') and (`test`.`t3`.`FOLDERNAME` = 'Level2') and (`test`.`t3`.`FOLDERNAME` = 'Level3') and (`test`.`t3`.`FOLDERNAME` = 'CopiedFolder') and (`test`.`t3`.`FOLDERNAME` = 'Movie Reviews') and (`test`.`t2`.`DOCNAME` = 'Last Discussion'))
+Note	1003	select `test`.`t2`.`DOCID` AS `DOCID`,`test`.`t2`.`DOCNAME` AS `DOCNAME`,`test`.`t2`.`DOCTYPEID` AS `DOCTYPEID`,`test`.`t2`.`FOLDERID` AS `FOLDERID`,`test`.`t2`.`AUTHOR` AS `AUTHOR`,`test`.`t2`.`CREATED` AS `CREATED`,`test`.`t2`.`TITLE` AS `TITLE`,`test`.`t2`.`SUBTITLE` AS `SUBTITLE`,`test`.`t2`.`DOCABSTRACT` AS `DOCABSTRACT`,`test`.`t2`.`PUBLISHDATE` AS `PUBLISHDATE`,`test`.`t2`.`EXPIRATIONDATE` AS `EXPIRATIONDATE`,`test`.`t2`.`LOCKEDBY` AS `LOCKEDBY`,`test`.`t2`.`STATUS` AS `STATUS`,`test`.`t2`.`PARENTDOCID` AS `PARENTDOCID`,`test`.`t2`.`REPID` AS `REPID`,`test`.`t2`.`MODIFIED` AS `MODIFIED`,`test`.`t2`.`MODIFIER` AS `MODIFIER`,`test`.`t2`.`PUBLISHSTATUS` AS `PUBLISHSTATUS`,`test`.`t2`.`ORIGINATOR` AS `ORIGINATOR`,`test`.`t4`.`DOCTYPENAME` AS `DOCTYPENAME`,`test`.`t1`.`CONTENTSIZE` AS `CONTENTSIZE`,`test`.`t1`.`MIMETYPE` AS `MIMETYPE` from `test`.`t2` join `test`.`t4` left join `test`.`t1` on((`test`.`t1`.`DOCID` = `test`.`t2`.`DOCID`)) where ((`test`.`t4`.`DOCTY
 PEID` = `test`.`t2`.`DOCTYPEID`) and (`test`.`t2`.`DOCNAME` = 'Last Discussion') and <in_optimizer>(`test`.`t2`.`FOLDERID`,<exists>(select 1 AS `Not_used` from `test`.`t3` join `test`.`t3` join `test`.`t3` join `test`.`t3` join `test`.`t3` where ((`test`.`t3`.`FOLDERID` = `test`.`t3`.`PARENTID`) and (`test`.`t3`.`FOLDERID` = `test`.`t3`.`PARENTID`) and (`test`.`t3`.`FOLDERID` = `test`.`t3`.`PARENTID`) and (`test`.`t3`.`FOLDERID` = `test`.`t3`.`PARENTID`) and (`test`.`t3`.`FOLDERNAME` = 'Level1') and (`test`.`t3`.`PARENTID` = '2f6161e879db43c1a5b82c21ddc49089') and (`test`.`t3`.`FOLDERNAME` = 'Level2') and (`test`.`t3`.`FOLDERNAME` = 'Level3') and (`test`.`t3`.`FOLDERNAME` = 'CopiedFolder') and (`test`.`t3`.`FOLDERNAME` = 'Movie Reviews') and (<cache>(`test`.`t2`.`FOLDERID`) = `test`.`t3`.`FOLDERID`)))))
 drop table t1, t2, t3, t4;
 CREATE TABLE t1 (a int(10) , PRIMARY KEY (a)) Engine=InnoDB;
 INSERT INTO t1 VALUES (1),(2);

=== modified file 'mysql-test/r/subselect3.result'
--- a/mysql-test/r/subselect3.result	2008-12-08 21:15:06 +0000
+++ b/mysql-test/r/subselect3.result	2008-12-23 04:05:29 +0000
@@ -1,4 +1,4 @@
-drop table if exists t0, t1, t2, t3, t4, t5;
+drop table if exists t0, t1, t2, t3, t4, t5, t11, t12, t21, t22;
 create table t1 (oref int, grp int, ie int) ;
 insert into t1 (oref, grp, ie) values
 (1, 1, 1),
@@ -99,7 +99,7 @@ oref	a
 1	1
 show status like '%Handler_read_rnd_next';
 Variable_name	Value
-Handler_read_rnd_next	11
+Handler_read_rnd_next	5
 delete from t2;
 insert into t2 values (NULL, 0),(NULL, 0), (NULL, 0), (NULL, 0);
 flush status;
@@ -337,8 +337,8 @@ dd	NULL	0
 bb	NULL	NULL
 select oref, a from t2 where a in (select ie from t1 where oref=t2.oref);
 oref	a
-aa	1
 ff	2
+aa	1
 select oref, a from t2 where a not in (select ie from t1 where oref=t2.oref);
 oref	a
 bb	2
@@ -421,8 +421,8 @@ dd	NULL	0
 bb	NULL	NULL
 select oref, a from t2 where a in (select ie from t1 where oref=t2.oref);
 oref	a
-aa	1
 ff	2
+aa	1
 select oref, a from t2 where a not in (select ie from t1 where oref=t2.oref);
 oref	a
 bb	2
@@ -515,8 +515,8 @@ aa	1	1	1
 dd	1	NULL	0
 select oref, a, b from t2 where (a,b) in (select ie1,ie2 from t1 where oref=t2.oref);
 oref	a	b
-aa	1	1
 ff	2	2
+aa	1	1
 select oref, a, b from t2 where (a,b) not in (select ie1,ie2 from t1 where oref=t2.oref);
 oref	a	b
 bb	2	1
@@ -560,8 +560,8 @@ aa	1	1	1
 dd	1	NULL	0
 select oref, a, b from t2 where (a,b) in (select ie1,ie2 from t1 where oref=t2.oref);
 oref	a	b
-aa	1	1
 ff	2	2
+aa	1	1
 select oref, a, b from t2 where (a,b) not in (select ie1,ie2 from t1 where oref=t2.oref);
 oref	a	b
 bb	2	1
@@ -838,6 +838,332 @@ t1.a < (select t4.a+10
 from t4, t5 limit 2));
 ERROR 21000: Subquery returns more than 1 row
 drop table t0, t1, t2, t3, t4, t5;
+CREATE TABLE t1 (
+a int(11) NOT NULL,
+b int(11) NOT NULL,
+c datetime default NULL,
+PRIMARY KEY  (a),
+KEY idx_bc (b,c)
+);
+INSERT INTO t1 VALUES 
+(406989,67,'2006-02-23 17:08:46'), (150078,67,'2005-10-26 11:17:45'),
+(406993,67,'2006-02-27 11:20:57'), (245655,67,'2005-12-08 15:59:08'),
+(406994,67,'2006-02-27 11:26:46'), (256,67,NULL),
+(398341,67,'2006-02-20 04:48:44'), (254,67,NULL),(1120,67,NULL),
+(406988,67,'2006-02-23 17:07:22'), (255,67,NULL),
+(398340,67,'2006-02-20 04:38:53'),(406631,67,'2006-02-23 10:49:42'),
+(245653,67,'2005-12-08 15:59:07'),(406992,67,'2006-02-24 16:47:18'),
+(245654,67,'2005-12-08 15:59:08'),(406995,67,'2006-02-28 11:55:00'),
+(127261,67,'2005-10-13 12:17:58'),(406991,67,'2006-02-24 16:42:32'),
+(245652,67,'2005-12-08 15:58:27'),(398545,67,'2006-02-20 04:53:13'),
+(154504,67,'2005-10-28 11:53:01'),(9199,67,NULL),(1,67,'2006-02-23 15:01:35'),
+(223456,67,NULL),(4101,67,NULL),(1133,67,NULL),
+(406990,67,'2006-02-23 18:01:45'),(148815,67,'2005-10-25 15:34:17'),
+(148812,67,'2005-10-25 15:30:01'),(245651,67,'2005-12-08 15:58:27'),
+(154503,67,'2005-10-28 11:52:38');
+create table t11 select * from t1 where b = 67 AND (c IS NULL OR c > NOW()) order by 3 asc;
+create table t12 select * from t1 where b = 67 AND (c IS NULL OR c > NOW()) order by 3 desc;
+create table t21 select * from t1 where b = 67 AND (c IS NULL OR c > '2005-12-08') order by 3 asc;
+create table t22 select * from t1 where b = 67 AND (c IS NULL OR c > '2005-12-08') order by 3 desc;
+update t22 set c = '2005-12-08 15:58:27' where a = 255;
+explain select t21.* from t21,t22 where t21.a = t22.a and 
+t22.a in (select t12.a from t11, t12 where t11.a in(255,256) and t11.a = t12.a and t11.c is null) and t22.c is null order by t21.a;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t11	ALL	NULL	NULL	NULL	NULL	8	Using where; Using temporary; Using filesort; Start materialize; Scan
+1	PRIMARY	t12	ALL	NULL	NULL	NULL	NULL	8	Using where; End materialize; Using join buffer
+1	PRIMARY	t21	ALL	NULL	NULL	NULL	NULL	26	Using where; Using join buffer
+1	PRIMARY	t22	ALL	NULL	NULL	NULL	NULL	32	Using where; Using join buffer
+select t21.* from t21,t22 where t21.a = t22.a and 
+t22.a in (select t12.a from t11, t12 where t11.a in(255,256) and t11.a = t12.a and t11.c is null) and t22.c is null order by t21.a;
+a	b	c
+256	67	NULL
+drop table t1, t11, t12, t21, t22;
+create table t1(a int);
+insert into t1 values (0),(1);
+set @@optimizer_switch='no_firstmatch';
+explain 
+select (select max(Y.a) from t1 Y where a in (select a from t1 Z) and a < X.a) as subq from t1 X;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	X	ALL	NULL	NULL	NULL	NULL	2	
+2	DEPENDENT SUBQUERY	Y	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	DEPENDENT SUBQUERY	Z	ALL	NULL	NULL	NULL	NULL	2	Materialize
+select (select max(Y.a) from t1 Y where a in (select a from t1 Z) and a < X.a) as subq from t1 X;
+subq
+NULL
+0
+set @@optimizer_switch='';
+drop table t1;
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t1 as select * from t0;
+insert into t1 select a+10 from t0;
+set @@optimizer_switch='no_firstmatch,no_materialization';
+insert into t0 values(2);
+explain select * from t1 where 2 in (select a from t0);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	11	Using where; Start temporary; End temporary
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	20	Using join buffer
+select * from t1 where 2 in (select a from t0);
+a
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+set @@optimizer_switch='no_materialization';
+explain select * from t1 where 2 in (select a from t0);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	11	Using where; FirstMatch
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	20	Using join buffer
+select * from t1 where 2 in (select a from t0);
+a
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+set @@optimizer_switch='';
+explain select * from (select a from t0) X where a in (select a from t1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	<derived2>	ALL	NULL	NULL	NULL	NULL	11	
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	20	Using where; FirstMatch(<derived2>)
+2	DERIVED	t0	ALL	NULL	NULL	NULL	NULL	11	
+drop table t0, t1;
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t1 (kp1 int, kp2 int, c int, filler char(100), key(kp1, kp2));
+insert into t1 select A.a+10*(B.a+10*C.a), 0, 0, 'filler' from t0 A, t0 B, t0 C;
+insert into t1 select * from t1 where kp1 < 20;
+create table t3 (a int);
+insert into t3 select A.a + 10*B.a from t0 A, t0 B;
+explain select * from t3 where a in (select kp1 from t1 where kp1<20);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	range	kp1	kp1	5	NULL	48	Using where; Using index; LooseScan
+1	PRIMARY	t3	ALL	NULL	NULL	NULL	NULL	100	Using where; Using join buffer
+create table t4 (pk int primary key);
+insert into t4 select a from t3;
+explain select * from t3 where a in (select t1.kp1 from t1,t4 where kp1<20
+and t4.pk=t1.c);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	range	kp1	kp1	5	NULL	48	Using index condition; Using MRR; LooseScan
+1	PRIMARY	t4	eq_ref	PRIMARY	PRIMARY	4	test.t1.c	1	Using index; FirstMatch(t1)
+1	PRIMARY	t3	ALL	NULL	NULL	NULL	NULL	100	Using where; Using join buffer
+drop table t1, t3, t4;
+create table t1 (a int) as select * from t0 where a < 5;
+set @save_max_heap_table_size=@@max_heap_table_size;
+set @@optimizer_switch='no_firstmatch,no_materialization';
+set @@max_heap_table_size= 16384;
+explain select count(*) from t0 A, t0 B, t0 C, t0 D where D.a in (select a from t1 E);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	E	ALL	NULL	NULL	NULL	NULL	5	Start temporary
+1	PRIMARY	A	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+1	PRIMARY	B	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+1	PRIMARY	C	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+1	PRIMARY	D	ALL	NULL	NULL	NULL	NULL	10	Using where; End temporary; Using join buffer
+flush status;
+select count(*) from t0 A, t0 B, t0 C, t0 D where D.a in (select a from t1 E);
+count(*)
+4999
+show status like 'Created_tmp_disk_tables';
+Variable_name	Value
+Created_tmp_disk_tables	1
+set @save_max_heap_table_size=@@max_heap_table_size;
+set @@optimizer_switch=default;
+drop table t0, t1;
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2(a int);
+insert into t2 values (1),(2);
+create table t3 ( a int , filler char(100), key(a));
+insert into t3 select A.a + 10*B.a, 'filler' from t0 A, t0 B;
+explain select * from t3 where a in (select a from t2) and (a > 5 or a < 10);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Using where; Materialize; Scan
+1	PRIMARY	t3	ref	a	a	5	test.t2.a	1	
+select * from t3 where a in (select a from t2);
+a	filler
+1	filler
+2	filler
+drop table t0, t2, t3;
+set @@optimizer_switch='no_firstmatch,no_materialization';
+create table t1 (a date);
+insert into t1 values ('2008-01-01'),('2008-01-01'),('2008-02-01'),('2008-02-01');
+create table t2 (a int);
+insert into t2 values (1),(2);
+create table t3 (a char(10));
+insert into t3 select * from t1;
+insert into t3 values (1),(2);
+explain select * from t2 where a in (select a from t1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Start temporary
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	4	Using where; End temporary; Using join buffer
+explain select * from t2 where a in (select a from t2);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Start temporary
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Using where; End temporary; Using join buffer
+explain select * from t2 where a in (select a from t3);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Start temporary
+1	PRIMARY	t3	ALL	NULL	NULL	NULL	NULL	6	Using where; End temporary; Using join buffer
+explain select * from t1 where a in (select a from t3);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	4	Start temporary
+1	PRIMARY	t3	ALL	NULL	NULL	NULL	NULL	6	Using where; End temporary; Using join buffer
+drop table t1, t2, t3;
+create table t1 (a decimal);
+insert into t1 values (1),(2);
+explain select * from t1 where a in (select a from t1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	Start temporary
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	Using where; End temporary; Using join buffer
+drop table t1;
+set @@optimizer_switch=default;
+create table t1 (a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2 as select * from t1;
+create table t3 (a int, b int, filler char(100), key(a));
+insert into t3 select A.a + 10*B.a, A.a + 10*B.a, 'filler' from t1 A, t1 B, t1 C;
+explain select * from t1, t3 where t3.a in (select a from t2) and (t3.a < 10 or t3.a >30) and t1.a =3;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	10	Using where
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	10	Using where; Materialize; Scan
+1	PRIMARY	t3	ref	a	a	5	test.t2.a	10	
+explain select straight_join * from t1 A, t1 B where A.a in (select a from t2);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	A	ALL	NULL	NULL	NULL	NULL	10	Using where
+1	PRIMARY	B	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	10	
+explain select * from t2 where a in (select straight_join A.a from t1 A, t1 B);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	10	Using where
+2	SUBQUERY	A	ALL	NULL	NULL	NULL	NULL	10	
+2	SUBQUERY	B	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+explain select * from t2 where a in (select straight_join A.a from t1 A, t1 B);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	10	Using where
+2	SUBQUERY	A	ALL	NULL	NULL	NULL	NULL	10	
+2	SUBQUERY	B	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+explain select straight_join * from t2 X, t2 Y 
+where X.a in (select straight_join A.a from t1 A, t1 B);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	X	ALL	NULL	NULL	NULL	NULL	10	Using where
+1	PRIMARY	Y	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+2	SUBQUERY	A	ALL	NULL	NULL	NULL	NULL	10	
+2	SUBQUERY	B	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+create table t0 (a int, b int);
+insert into t0 values(1,1);
+explain select * from t0, t3 where t3.a in (select a from t2) and (t3.a < 10 or t3.a >30);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t0	system	NULL	NULL	NULL	NULL	1	
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	10	Using where; Materialize; Scan
+1	PRIMARY	t3	ref	a	a	5	test.t2.a	10	
+create table t4 as select a as x, a as y from t1;
+explain select * from t0, t3 where (t3.a, t3.b) in (select x,y from t4) and (t3.a < 10 or t3.a >30);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t0	system	NULL	NULL	NULL	NULL	1	
+1	PRIMARY	t4	ALL	NULL	NULL	NULL	NULL	10	Using where; Materialize; Scan
+1	PRIMARY	t3	ref	a	a	5	test.t4.x	10	Using where
+drop table t0,t1,t2,t3,t4;
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t1 (a int, b int, filler char(100), key(a,b));
+insert into t1 select A.a, B.a, 'filler' from t0 A, t0 B;
+create table t2 as select * from t1;
+explain select * from t2 where a in (select b from t1 where a=3);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	range	a	a	5	NULL	8	Using where; Using index; LooseScan
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	100	Using where; Using join buffer
+explain select * from t2 where (b,a) in (select a,b from t1 where a=3);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	range	a	a	5	NULL	8	Using where; Using index; LooseScan
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	100	Using where; Using join buffer
+drop table t1,t2;
+create table t1 (a int, b int);
+insert into t1 select a,a from t0;
+create table t2 (a int, b int);
+insert into t2 select A.a + 10*B.a, A.a + 10*B.a from t0 A, t0 B;
+set @@optimizer_switch='no_firstmatch';
+explain select * from t1 where (a,b) in (select a,b from t2);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	10	
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	100	Materialize
+set @save_optimizer_search_depth=@@optimizer_search_depth;
+set @@optimizer_search_depth=63;
+explain select * from t1 where (a,b) in (select a,b from t2);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	10	
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	100	Materialize
+set @@optimizer_search_depth=@save_optimizer_search_depth;
+set @@optimizer_switch='';
+drop table t0, t1, t2;
+create table t0 (a decimal(4,2));
+insert into t0 values (10.24), (22.11);
+create table t1 as select * from t0;
+insert into t1 select * from t0;
+explain select * from t0 where a in (select a from t1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	2	
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	4	Using where; FirstMatch(t0)
+select * from t0 where a in (select a from t1);
+a
+10.24
+22.11
+drop table t0, t1;
+create table t0(a date);
+insert into t0 values ('2008-01-01'),('2008-02-02');
+create table t1 as select * from t0;
+insert into t1 select * from t0;
+explain select * from t0 where a in (select a from t1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	2	
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	4	Using where; FirstMatch(t0)
+select * from t0 where a in (select a from t1);
+a
+2008-01-01
+2008-02-02
+drop table t0, t1;
+create table t0(a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t1 as select a as a, a as b, a as c from t0 where a < 3;
+create table t2 as select a as a, a as b from t0 where a < 3;
+insert into t2 select * from t2;
+explain select * from t1 where (a,b,c) in (select X.a, Y.a, Z.a from t2 X, t2 Y, t2 Z where X.b=33);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	
+1	PRIMARY	X	ALL	NULL	NULL	NULL	NULL	6	Using where; Start materialize
+1	PRIMARY	Y	ALL	NULL	NULL	NULL	NULL	6	Using join buffer
+1	PRIMARY	Z	ALL	NULL	NULL	NULL	NULL	6	End materialize; Using join buffer
+drop table t0,t1,t2;
 
 BUG#40118 Crash when running Batched Key Access and requiring one match for each key
 

=== modified file 'mysql-test/r/subselect3_jcl6.result'
--- a/mysql-test/r/subselect3_jcl6.result	2008-12-08 21:15:06 +0000
+++ b/mysql-test/r/subselect3_jcl6.result	2008-12-23 04:05:29 +0000
@@ -2,7 +2,7 @@ set join_cache_level=6;
 show variables like 'join_cache_level';
 Variable_name	Value
 join_cache_level	6
-drop table if exists t0, t1, t2, t3, t4, t5;
+drop table if exists t0, t1, t2, t3, t4, t5, t11, t12, t21, t22;
 create table t1 (oref int, grp int, ie int) ;
 insert into t1 (oref, grp, ie) values
 (1, 1, 1),
@@ -103,7 +103,7 @@ oref	a
 1	1
 show status like '%Handler_read_rnd_next';
 Variable_name	Value
-Handler_read_rnd_next	11
+Handler_read_rnd_next	5
 delete from t2;
 insert into t2 values (NULL, 0),(NULL, 0), (NULL, 0), (NULL, 0);
 flush status;
@@ -842,6 +842,333 @@ t1.a < (select t4.a+10
 from t4, t5 limit 2));
 ERROR 21000: Subquery returns more than 1 row
 drop table t0, t1, t2, t3, t4, t5;
+CREATE TABLE t1 (
+a int(11) NOT NULL,
+b int(11) NOT NULL,
+c datetime default NULL,
+PRIMARY KEY  (a),
+KEY idx_bc (b,c)
+);
+INSERT INTO t1 VALUES 
+(406989,67,'2006-02-23 17:08:46'), (150078,67,'2005-10-26 11:17:45'),
+(406993,67,'2006-02-27 11:20:57'), (245655,67,'2005-12-08 15:59:08'),
+(406994,67,'2006-02-27 11:26:46'), (256,67,NULL),
+(398341,67,'2006-02-20 04:48:44'), (254,67,NULL),(1120,67,NULL),
+(406988,67,'2006-02-23 17:07:22'), (255,67,NULL),
+(398340,67,'2006-02-20 04:38:53'),(406631,67,'2006-02-23 10:49:42'),
+(245653,67,'2005-12-08 15:59:07'),(406992,67,'2006-02-24 16:47:18'),
+(245654,67,'2005-12-08 15:59:08'),(406995,67,'2006-02-28 11:55:00'),
+(127261,67,'2005-10-13 12:17:58'),(406991,67,'2006-02-24 16:42:32'),
+(245652,67,'2005-12-08 15:58:27'),(398545,67,'2006-02-20 04:53:13'),
+(154504,67,'2005-10-28 11:53:01'),(9199,67,NULL),(1,67,'2006-02-23 15:01:35'),
+(223456,67,NULL),(4101,67,NULL),(1133,67,NULL),
+(406990,67,'2006-02-23 18:01:45'),(148815,67,'2005-10-25 15:34:17'),
+(148812,67,'2005-10-25 15:30:01'),(245651,67,'2005-12-08 15:58:27'),
+(154503,67,'2005-10-28 11:52:38');
+create table t11 select * from t1 where b = 67 AND (c IS NULL OR c > NOW()) order by 3 asc;
+create table t12 select * from t1 where b = 67 AND (c IS NULL OR c > NOW()) order by 3 desc;
+create table t21 select * from t1 where b = 67 AND (c IS NULL OR c > '2005-12-08') order by 3 asc;
+create table t22 select * from t1 where b = 67 AND (c IS NULL OR c > '2005-12-08') order by 3 desc;
+update t22 set c = '2005-12-08 15:58:27' where a = 255;
+explain select t21.* from t21,t22 where t21.a = t22.a and 
+t22.a in (select t12.a from t11, t12 where t11.a in(255,256) and t11.a = t12.a and t11.c is null) and t22.c is null order by t21.a;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t11	ALL	NULL	NULL	NULL	NULL	8	Using where; Using temporary; Using filesort; Start materialize; Scan
+1	PRIMARY	t12	ALL	NULL	NULL	NULL	NULL	8	Using where; End materialize; Using join buffer
+1	PRIMARY	t21	ALL	NULL	NULL	NULL	NULL	26	Using where; Using join buffer
+1	PRIMARY	t22	ALL	NULL	NULL	NULL	NULL	32	Using where; Using join buffer
+select t21.* from t21,t22 where t21.a = t22.a and 
+t22.a in (select t12.a from t11, t12 where t11.a in(255,256) and t11.a = t12.a and t11.c is null) and t22.c is null order by t21.a;
+a	b	c
+256	67	NULL
+256	67	NULL
+drop table t1, t11, t12, t21, t22;
+create table t1(a int);
+insert into t1 values (0),(1);
+set @@optimizer_switch='no_firstmatch';
+explain 
+select (select max(Y.a) from t1 Y where a in (select a from t1 Z) and a < X.a) as subq from t1 X;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	X	ALL	NULL	NULL	NULL	NULL	2	
+2	DEPENDENT SUBQUERY	Y	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	DEPENDENT SUBQUERY	Z	ALL	NULL	NULL	NULL	NULL	2	Materialize
+select (select max(Y.a) from t1 Y where a in (select a from t1 Z) and a < X.a) as subq from t1 X;
+subq
+NULL
+0
+set @@optimizer_switch='';
+drop table t1;
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t1 as select * from t0;
+insert into t1 select a+10 from t0;
+set @@optimizer_switch='no_firstmatch,no_materialization';
+insert into t0 values(2);
+explain select * from t1 where 2 in (select a from t0);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	11	Using where; Start temporary; End temporary
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	20	Using join buffer
+select * from t1 where 2 in (select a from t0);
+a
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+set @@optimizer_switch='no_materialization';
+explain select * from t1 where 2 in (select a from t0);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	11	Using where; FirstMatch
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	20	Using join buffer
+select * from t1 where 2 in (select a from t0);
+a
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+set @@optimizer_switch='';
+explain select * from (select a from t0) X where a in (select a from t1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	<derived2>	ALL	NULL	NULL	NULL	NULL	11	
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	20	Using where; FirstMatch(<derived2>); Using join buffer
+2	DERIVED	t0	ALL	NULL	NULL	NULL	NULL	11	
+drop table t0, t1;
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t1 (kp1 int, kp2 int, c int, filler char(100), key(kp1, kp2));
+insert into t1 select A.a+10*(B.a+10*C.a), 0, 0, 'filler' from t0 A, t0 B, t0 C;
+insert into t1 select * from t1 where kp1 < 20;
+create table t3 (a int);
+insert into t3 select A.a + 10*B.a from t0 A, t0 B;
+explain select * from t3 where a in (select kp1 from t1 where kp1<20);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	range	kp1	kp1	5	NULL	48	Using where; Using index; LooseScan
+1	PRIMARY	t3	ALL	NULL	NULL	NULL	NULL	100	Using where; Using join buffer
+create table t4 (pk int primary key);
+insert into t4 select a from t3;
+explain select * from t3 where a in (select t1.kp1 from t1,t4 where kp1<20
+and t4.pk=t1.c);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	range	kp1	kp1	5	NULL	48	Using index condition; Using MRR; LooseScan
+1	PRIMARY	t4	eq_ref	PRIMARY	PRIMARY	4	test.t1.c	1	Using index; FirstMatch(t1)
+1	PRIMARY	t3	ALL	NULL	NULL	NULL	NULL	100	Using where; Using join buffer
+drop table t1, t3, t4;
+create table t1 (a int) as select * from t0 where a < 5;
+set @save_max_heap_table_size=@@max_heap_table_size;
+set @@optimizer_switch='no_firstmatch,no_materialization';
+set @@max_heap_table_size= 16384;
+explain select count(*) from t0 A, t0 B, t0 C, t0 D where D.a in (select a from t1 E);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	E	ALL	NULL	NULL	NULL	NULL	5	Start temporary
+1	PRIMARY	A	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+1	PRIMARY	B	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+1	PRIMARY	C	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+1	PRIMARY	D	ALL	NULL	NULL	NULL	NULL	10	Using where; End temporary; Using join buffer
+flush status;
+select count(*) from t0 A, t0 B, t0 C, t0 D where D.a in (select a from t1 E);
+count(*)
+4999
+show status like 'Created_tmp_disk_tables';
+Variable_name	Value
+Created_tmp_disk_tables	1
+set @save_max_heap_table_size=@@max_heap_table_size;
+set @@optimizer_switch=default;
+drop table t0, t1;
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2(a int);
+insert into t2 values (1),(2);
+create table t3 ( a int , filler char(100), key(a));
+insert into t3 select A.a + 10*B.a, 'filler' from t0 A, t0 B;
+explain select * from t3 where a in (select a from t2) and (a > 5 or a < 10);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Using where; Materialize; Scan
+1	PRIMARY	t3	ref	a	a	5	test.t2.a	1	Using join buffer
+select * from t3 where a in (select a from t2);
+a	filler
+1	filler
+2	filler
+drop table t0, t2, t3;
+set @@optimizer_switch='no_firstmatch,no_materialization';
+create table t1 (a date);
+insert into t1 values ('2008-01-01'),('2008-01-01'),('2008-02-01'),('2008-02-01');
+create table t2 (a int);
+insert into t2 values (1),(2);
+create table t3 (a char(10));
+insert into t3 select * from t1;
+insert into t3 values (1),(2);
+explain select * from t2 where a in (select a from t1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Start temporary
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	4	Using where; End temporary; Using join buffer
+explain select * from t2 where a in (select a from t2);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Start temporary
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Using where; End temporary; Using join buffer
+explain select * from t2 where a in (select a from t3);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Start temporary
+1	PRIMARY	t3	ALL	NULL	NULL	NULL	NULL	6	Using where; End temporary; Using join buffer
+explain select * from t1 where a in (select a from t3);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	4	Start temporary
+1	PRIMARY	t3	ALL	NULL	NULL	NULL	NULL	6	Using where; End temporary; Using join buffer
+drop table t1, t2, t3;
+create table t1 (a decimal);
+insert into t1 values (1),(2);
+explain select * from t1 where a in (select a from t1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	Start temporary
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	Using where; End temporary; Using join buffer
+drop table t1;
+set @@optimizer_switch=default;
+create table t1 (a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2 as select * from t1;
+create table t3 (a int, b int, filler char(100), key(a));
+insert into t3 select A.a + 10*B.a, A.a + 10*B.a, 'filler' from t1 A, t1 B, t1 C;
+explain select * from t1, t3 where t3.a in (select a from t2) and (t3.a < 10 or t3.a >30) and t1.a =3;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	10	Using where
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	10	Using where; Materialize; Scan
+1	PRIMARY	t3	ref	a	a	5	test.t2.a	10	Using join buffer
+explain select straight_join * from t1 A, t1 B where A.a in (select a from t2);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	A	ALL	NULL	NULL	NULL	NULL	10	Using where
+1	PRIMARY	B	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	10	
+explain select * from t2 where a in (select straight_join A.a from t1 A, t1 B);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	10	Using where
+2	SUBQUERY	A	ALL	NULL	NULL	NULL	NULL	10	
+2	SUBQUERY	B	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+explain select * from t2 where a in (select straight_join A.a from t1 A, t1 B);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	10	Using where
+2	SUBQUERY	A	ALL	NULL	NULL	NULL	NULL	10	
+2	SUBQUERY	B	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+explain select straight_join * from t2 X, t2 Y 
+where X.a in (select straight_join A.a from t1 A, t1 B);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	X	ALL	NULL	NULL	NULL	NULL	10	Using where
+1	PRIMARY	Y	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+2	SUBQUERY	A	ALL	NULL	NULL	NULL	NULL	10	
+2	SUBQUERY	B	ALL	NULL	NULL	NULL	NULL	10	Using join buffer
+create table t0 (a int, b int);
+insert into t0 values(1,1);
+explain select * from t0, t3 where t3.a in (select a from t2) and (t3.a < 10 or t3.a >30);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t0	system	NULL	NULL	NULL	NULL	1	
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	10	Using where; Materialize; Scan
+1	PRIMARY	t3	ref	a	a	5	test.t2.a	10	Using join buffer
+create table t4 as select a as x, a as y from t1;
+explain select * from t0, t3 where (t3.a, t3.b) in (select x,y from t4) and (t3.a < 10 or t3.a >30);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t0	system	NULL	NULL	NULL	NULL	1	
+1	PRIMARY	t4	ALL	NULL	NULL	NULL	NULL	10	Using where; Materialize; Scan
+1	PRIMARY	t3	ref	a	a	5	test.t4.x	10	Using where; Using join buffer
+drop table t0,t1,t2,t3,t4;
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t1 (a int, b int, filler char(100), key(a,b));
+insert into t1 select A.a, B.a, 'filler' from t0 A, t0 B;
+create table t2 as select * from t1;
+explain select * from t2 where a in (select b from t1 where a=3);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	range	a	a	5	NULL	8	Using where; Using index; LooseScan
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	100	Using where; Using join buffer
+explain select * from t2 where (b,a) in (select a,b from t1 where a=3);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	range	a	a	5	NULL	8	Using where; Using index; LooseScan
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	100	Using where; Using join buffer
+drop table t1,t2;
+create table t1 (a int, b int);
+insert into t1 select a,a from t0;
+create table t2 (a int, b int);
+insert into t2 select A.a + 10*B.a, A.a + 10*B.a from t0 A, t0 B;
+set @@optimizer_switch='no_firstmatch';
+explain select * from t1 where (a,b) in (select a,b from t2);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	10	
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	100	Materialize
+set @save_optimizer_search_depth=@@optimizer_search_depth;
+set @@optimizer_search_depth=63;
+explain select * from t1 where (a,b) in (select a,b from t2);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	10	
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	100	Materialize
+set @@optimizer_search_depth=@save_optimizer_search_depth;
+set @@optimizer_switch='';
+drop table t0, t1, t2;
+create table t0 (a decimal(4,2));
+insert into t0 values (10.24), (22.11);
+create table t1 as select * from t0;
+insert into t1 select * from t0;
+explain select * from t0 where a in (select a from t1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	2	
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	4	Using where; FirstMatch(t0); Using join buffer
+select * from t0 where a in (select a from t1);
+a
+10.24
+22.11
+drop table t0, t1;
+create table t0(a date);
+insert into t0 values ('2008-01-01'),('2008-02-02');
+create table t1 as select * from t0;
+insert into t1 select * from t0;
+explain select * from t0 where a in (select a from t1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	2	
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	4	Using where; FirstMatch(t0); Using join buffer
+select * from t0 where a in (select a from t1);
+a
+2008-01-01
+2008-02-02
+drop table t0, t1;
+create table t0(a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t1 as select a as a, a as b, a as c from t0 where a < 3;
+create table t2 as select a as a, a as b from t0 where a < 3;
+insert into t2 select * from t2;
+explain select * from t1 where (a,b,c) in (select X.a, Y.a, Z.a from t2 X, t2 Y, t2 Z where X.b=33);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	
+1	PRIMARY	X	ALL	NULL	NULL	NULL	NULL	6	Using where; Start materialize
+1	PRIMARY	Y	ALL	NULL	NULL	NULL	NULL	6	Using join buffer
+1	PRIMARY	Z	ALL	NULL	NULL	NULL	NULL	6	End materialize; Using join buffer
+drop table t0,t1,t2;
 
 BUG#40118 Crash when running Batched Key Access and requiring one match for each key
 

=== modified file 'mysql-test/r/subselect_mat.result'
--- a/mysql-test/r/subselect_mat.result	2008-04-24 23:59:38 +0000
+++ b/mysql-test/r/subselect_mat.result	2008-11-26 14:36:11 +0000
@@ -41,7 +41,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	5	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( <materialize> (select `test`.`t2`.`b1` AS `b1` from `test`.`t2` where (`test`.`t2`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( <materialize> (select `test`.`t2`.`b1` AS `b1` from `test`.`t2` where (`test`.`t2`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`b1`)))))
 select * from t1 where a1 in (select b1 from t2 where b1 > '0');
 a1	a2
 1 - 01	2 - 01
@@ -52,7 +52,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	5	100.00	Using where; Using temporary; Using filesort
 Warnings:
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( <materialize> (select `test`.`t2`.`b1` AS `b1` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( <materialize> (select `test`.`t2`.`b1` AS `b1` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`b1`)))))
 select * from t1 where a1 in (select b1 from t2 where b1 > '0' group by b1);
 a1	a2
 1 - 01	2 - 01
@@ -63,7 +63,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	5	100.00	Using where; Using temporary; Using filesort
 Warnings:
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1`,`test`.`t2`.`b2` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1`,`test`.`t2`.`b2` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1`.`a2` = `materialized subselect`.`b2`)))))
 select * from t1 where (a1, a2) in (select b1, b2 from t2 where b1 > '0' group by b1, b2);
 a1	a2
 1 - 01	2 - 01
@@ -74,7 +74,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	5	100.00	Using where; Using temporary; Using filesort
 Warnings:
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2`.`b1` AS `b1`,min(`test`.`t2`.`b2`) AS `min(b2)` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2`.`b1` AS `b1`,min(`test`.`t2`.`b2`) AS `min(b2)` from `test`.`t2` where (`test`.`t2`.`b1` > '0') group by `test`.`t2`.`b1` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1`.`a2` = `materialized subselect`.`min(b2)`)))))
 select * from t1 where (a1, a2) in (select b1, min(b2) from t2 where b1 > '0' group by b1);
 a1	a2
 1 - 01	2 - 01
@@ -85,7 +85,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1i	index	NULL	it1i3	18	NULL	3	100.00	Using where; Using index
 2	SUBQUERY	t2i	index	it2i1,it2i3	it2i1	9	NULL	5	100.00	Using where; Using index
 Warnings:
-Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <in_optimizer>(`test`.`t1i`.`a1`,`test`.`t1i`.`a1` in ( <materialize> (select `test`.`t2i`.`b1` AS `b1` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <in_optimizer>(`test`.`t1i`.`a1`,`test`.`t1i`.`a1` in ( <materialize> (select `test`.`t2i`.`b1` AS `b1` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key where ((`test`.`t1i`.`a1` = `materialized subselect`.`b1`)))))
 select * from t1i where a1 in (select b1 from t2i where b1 > '0');
 a1	a2
 1 - 01	2 - 01
@@ -96,7 +96,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1i	index	NULL	it1i3	18	NULL	3	100.00	Using where; Using index
 2	SUBQUERY	t2i	range	it2i1,it2i3	it2i1	9	NULL	3	100.00	Using where; Using index for group-by
 Warnings:
-Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <in_optimizer>(`test`.`t1i`.`a1`,`test`.`t1i`.`a1` in ( <materialize> (select `test`.`t2i`.`b1` AS `b1` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <in_optimizer>(`test`.`t1i`.`a1`,`test`.`t1i`.`a1` in ( <materialize> (select `test`.`t2i`.`b1` AS `b1` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key where ((`test`.`t1i`.`a1` = `materialized subselect`.`b1`)))))
 select * from t1i where a1 in (select b1 from t2i where b1 > '0' group by b1);
 a1	a2
 1 - 01	2 - 01
@@ -107,7 +107,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1i	index	NULL	it1i3	18	NULL	3	100.00	Using where; Using index
 2	SUBQUERY	t2i	index	it2i1,it2i3	it2i3	18	NULL	5	100.00	Using where; Using index
 Warnings:
-Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key where ((`test`.`t1i`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1i`.`a2` = `materialized subselect`.`b2`)))))
 select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0');
 a1	a2
 1 - 01	2 - 01
@@ -118,7 +118,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1i	index	NULL	it1i3	18	NULL	3	100.00	Using where; Using index
 2	SUBQUERY	t2i	range	it2i1,it2i3	it2i3	18	NULL	3	100.00	Using where; Using index for group-by
 Warnings:
-Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`,`test`.`t2i`.`b2` ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1`,`test`.`t2i`.`b2` ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key where ((`test`.`t1i`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1i`.`a2` = `materialized subselect`.`b2`)))))
 select * from t1i where (a1, a2) in (select b1, b2 from t2i where b1 > '0' group by b1, b2);
 a1	a2
 1 - 01	2 - 01
@@ -129,7 +129,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1i	index	NULL	it1i3	18	NULL	3	100.00	Using where; Using index
 2	SUBQUERY	t2i	range	it2i1,it2i3	it2i3	18	NULL	3	100.00	Using where; Using index for group-by
 Warnings:
-Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,min(`test`.`t2i`.`b2`) AS `min(b2)` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,min(`test`.`t2i`.`b2`) AS `min(b2)` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key where ((`test`.`t1i`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1i`.`a2` = `materialized subselect`.`min(b2)`)))))
 select * from t1i where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' group by b1);
 a1	a2
 1 - 01	2 - 01
@@ -140,7 +140,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2i	range	NULL	it2i3	9	NULL	3	100.00	Using index for group-by
 Warnings:
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,max(`test`.`t2i`.`b2`) AS `max(b2)` from `test`.`t2i` group by `test`.`t2i`.`b1` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,max(`test`.`t2i`.`b2`) AS `max(b2)` from `test`.`t2i` group by `test`.`t2i`.`b1` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1`.`a2` = `materialized subselect`.`max(b2)`)))))
 select * from t1 where (a1, a2) in (select b1, max(b2) from t2i group by b1);
 a1	a2
 1 - 01	2 - 01
@@ -169,7 +169,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2i	range	it2i1,it2i3	it2i3	18	NULL	3	100.00	Using where; Using index for group-by
 Warnings:
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,min(`test`.`t2i`.`b2`) AS `min(b2)` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,min(`test`.`t2i`.`b2`) AS `min(b2)` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') group by `test`.`t2i`.`b1` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1`.`a2` = `materialized subselect`.`min(b2)`)))))
 select * from t1 where (a1, a2) in (select b1, min(b2) from t2i where b1 > '0' group by b1);
 a1	a2
 1 - 01	2 - 01
@@ -209,7 +209,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	5	100.00	
 Warnings:
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` order by `test`.`t2`.`b1`,`test`.`t2`.`b2` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` order by `test`.`t2`.`b1`,`test`.`t2`.`b2` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1`.`a2` = `materialized subselect`.`b2`)))))
 select * from t1 where (a1, a2) in (select b1, b2 from t2 order by b1, b2);
 a1	a2
 1 - 01	2 - 01
@@ -220,7 +220,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1i	index	NULL	it1i3	18	NULL	3	100.00	Using where; Using index
 2	SUBQUERY	t2i	index	NULL	it2i3	18	NULL	5	100.00	Using index
 Warnings:
-Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` order by `test`.`t2i`.`b1`,`test`.`t2i`.`b2` ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where <in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` order by `test`.`t2i`.`b1`,`test`.`t2i`.`b2` ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key where ((`test`.`t1i`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1i`.`a2` = `materialized subselect`.`b2`)))))
 select * from t1i where (a1, a2) in (select b1, b2 from t2i order by b1, b2);
 a1	a2
 1 - 01	2 - 01
@@ -275,7 +275,7 @@ id	select_type	table	type	possible_keys
 4	SUBQUERY	t2i	index	it2i2	it2i3	18	NULL	5	100.00	Using where; Using index
 2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	5	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where (`test`.`t2`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key))) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t3` where <in_optimizer>((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3`.`c1` in <temporary table> on distinct_key))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key))))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where (`test`.`t2`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1`.`a2` = `materialized subselect`.`b2`))))) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t3` where <in_optimizer>((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3`.`c1` in <temporary table> on distinct_key wh
 ere ((`test`.`t3`.`c1` = `materialized subselect`.`b1`) and (`test`.`t3`.`c2` = `materialized subselect`.`b2`))))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`c1`) and (`test`.`t1`.`a2` = `materialized subselect`.`c2`))))))
 select * from t1
 where (a1, a2) in (select b1, b2 from t2 where b1 >  '0') and
 (a1, a2) in (select c1, c2 from t3
@@ -294,7 +294,7 @@ id	select_type	table	type	possible_keys
 4	SUBQUERY	t2i	index	it2i2	it2i3	18	NULL	5	100.00	Using where; Using index
 2	SUBQUERY	t2i	index	it2i1,it2i3	it2i3	18	NULL	5	100.00	Using where; Using index
 Warnings:
-Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where (<in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key))) and <in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t3i`.`c1` AS `c1`,`test`.`t3i`.`c2` AS `c2` from `test`.`t3i` where <in_optimizer>((`test`.`t3i`.`c1`,`test`.`t3i`.`c2`),(`test`.`t3i`.`c1`,`test`.`t3i`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3i`.`c1` in <temporary table> on distinct_key))) ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key))))
+Note	1003	select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where (<in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key where ((`test`.`t1i`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1i`.`a2` = `materialized subselect`.`b2`))))) and <in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t3i`.`c1` AS `c1`,`test`.`t3i`.`c2` AS `c2` from `test`.`t3i` where <in_optimizer>((`test`.`t3i`.`c1`,`test`.`t3i`.`c2`),(`test`.`t3i`.`c1`,`test`.`t3i`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3i`.`c1` in <temporary
  table> on distinct_key where ((`test`.`t3i`.`c1` = `materialized subselect`.`b1`) and (`test`.`t3i`.`c2` = `materialized subselect`.`b2`))))) ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key where ((`test`.`t1i`.`a1` = `materialized subselect`.`c1`) and (`test`.`t1i`.`a2` = `materialized subselect`.`c2`))))))
 select * from t1i
 where (a1, a2) in (select b1, b2 from t2i where b1 >  '0') and
 (a1, a2) in (select c1, c2 from t3i
@@ -317,7 +317,7 @@ id	select_type	table	type	possible_keys
 4	SUBQUERY	t3	ALL	NULL	NULL	NULL	NULL	4	100.00	Using where
 3	SUBQUERY	t3	ALL	NULL	NULL	NULL	NULL	4	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where (<in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (select `test`.`t3`.`c2` AS `c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key))) or <in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (select `test`.`t3`.`c2` AS `c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key)))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key))) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t3`.`c1` AS `c1`,`test`
 .`t3`.`c2` AS `c2` from `test`.`t3` where <in_optimizer>((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3`.`c1` in <temporary table> on distinct_key))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key))))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where (<in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (select `test`.`t3`.`c2` AS `c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key where ((`test`.`t2`.`b2` = `materialized subselect`.`c2`))))) or <in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (select `test`.`t3`.`c2` AS `c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key where ((`test`.`t2`.`b2` = `materialized subselect`.`c2`)))))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materi
 alized subselect`.`b1`) and (`test`.`t1`.`a2` = `materialized subselect`.`b2`))))) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t3` where <in_optimizer>((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3`.`c1` in <temporary table> on distinct_key where ((`test`.`t3`.`c1` = `materialized subselect`.`b1`) and (`test`.`t3`.`c2` = `materialized subselect`.`b2`))))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`c1`) and (`test`.`t1`.`a2` = `materialized subselect`.`c2`))))))
 select * from t1
 where (a1, a2) in (select b1, b2 from t2
 where b2 in (select c2 from t3 where c2 LIKE '%02') or
@@ -342,7 +342,7 @@ id	select_type	table	type	possible_keys
 3	DEPENDENT SUBQUERY	t3a	ALL	NULL	NULL	NULL	NULL	4	100.00	Using where
 Warnings:
 Note	1276	Field or reference 'test.t1.a1' of SELECT #3 was resolved in SELECT #1
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where ((<in_optimizer>(`test`.`t2`.`b2`,<exists>(select 1 AS `Not_used` from `test`.`t3` `t3a` where ((`test`.`t3a`.`c1` = `test`.`t1`.`a1`) and (<cache>(`test`.`t2`.`b2`) = `test`.`t3a`.`c2`)))) or <in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (select `test`.`t3b`.`c2` AS `c2` from `test`.`t3` `t3b` where (`test`.`t3b`.`c2` like '%03') ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key)))) and (<cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`)))) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t3c`.`c1` AS `c1`,`test`.`t3c`.`c2` AS `c2` from `test`.`t3` `t3c` where <in_optimizer>(
 (`test`.`t3c`.`c1`,`test`.`t3c`.`c2`),(`test`.`t3c`.`c1`,`test`.`t3c`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3c`.`c1` in <temporary table> on distinct_key))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key))))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where ((<in_optimizer>(`test`.`t2`.`b2`,<exists>(select 1 AS `Not_used` from `test`.`t3` `t3a` where ((`test`.`t3a`.`c1` = `test`.`t1`.`a1`) and (<cache>(`test`.`t2`.`b2`) = `test`.`t3a`.`c2`)))) or <in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (select `test`.`t3b`.`c2` AS `c2` from `test`.`t3` `t3b` where (`test`.`t3b`.`c2` like '%03') ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key where ((`test`.`t2`.`b2` = `materialized subselect`.`c2`)))))) and (<cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`)))) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t3c`.`c1` AS `c1`,`test`.`t3c
 `.`c2` AS `c2` from `test`.`t3` `t3c` where <in_optimizer>((`test`.`t3c`.`c1`,`test`.`t3c`.`c2`),(`test`.`t3c`.`c1`,`test`.`t3c`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3c`.`c1` in <temporary table> on distinct_key where ((`test`.`t3c`.`c1` = `materialized subselect`.`b1`) and (`test`.`t3c`.`c2` = `materialized subselect`.`b2`))))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`c1`) and (`test`.`t1`.`a2` = `materialized subselect`.`c2`))))))
 select * from t1
 where (a1, a2) in (select b1, b2 from t2
 where b2 in (select c2 from t3 t3a where c1 = a1) or
@@ -378,7 +378,7 @@ id	select_type	table	type	possible_keys
 8	SUBQUERY	t2i	index	it2i1,it2i3	it2i3	18	NULL	5	100.00	Using where; Using index
 NULL	UNION RESULT	<union1,7>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
 Warnings:
-Note	1003	(select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where (<in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (select `test`.`t3`.`c2` AS `c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key))) or <in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (select `test`.`t3`.`c2` AS `c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key)))) group by `test`.`t2`.`b1`,`test`.`t2`.`b2` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key))) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <material
 ize> (select `test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t3` where <in_optimizer>((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3`.`c1` in <temporary table> on distinct_key))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key))))) union (select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` AS `a2` from `test`.`t1i` where (<in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key))) and <in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `t
 est`.`t3i`.`c1` AS `c1`,`test`.`t3i`.`c2` AS `c2` from `test`.`t3i` where <in_optimizer>((`test`.`t3i`.`c1`,`test`.`t3i`.`c2`),(`test`.`t3i`.`c1`,`test`.`t3i`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3i`.`c1` in <temporary table> on distinct_key))) ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key)))))
+Note	1003	(select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where (<in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (select `test`.`t3`.`c2` AS `c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%02') ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key where ((`test`.`t2`.`b2` = `materialized subselect`.`c2`))))) or <in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (select `test`.`t3`.`c2` AS `c2` from `test`.`t3` where (`test`.`t3`.`c2` like '%03') ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key where ((`test`.`t2`.`b2` = `materialized subselect`.`c2`)))))) group by `test`.`t2`.`b1`,`test`.`t2`.`b2` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on dis
 tinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1`.`a2` = `materialized subselect`.`b2`))))) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t3` where <in_optimizer>((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3`.`c1` in <temporary table> on distinct_key where ((`test`.`t3`.`c1` = `materialized subselect`.`b1`) and (`test`.`t3`.`c2` = `materialized subselect`.`b2`))))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`c1`) and (`test`.`t1`.`a2` = `materialized subselect`.`c2`))))))) union (select `test`.`t1i`.`a1` AS `a1`,`test`.`t1i`.`a2` A
 S `a2` from `test`.`t1i` where (<in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key where ((`test`.`t1i`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1i`.`a2` = `materialized subselect`.`b2`))))) and <in_optimizer>((`test`.`t1i`.`a1`,`test`.`t1i`.`a2`),(`test`.`t1i`.`a1`,`test`.`t1i`.`a2`) in ( <materialize> (select `test`.`t3i`.`c1` AS `c1`,`test`.`t3i`.`c2` AS `c2` from `test`.`t3i` where <in_optimizer>((`test`.`t3i`.`c1`,`test`.`t3i`.`c2`),(`test`.`t3i`.`c1`,`test`.`t3i`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3i`.`c1` in <temporary table> on distinct_key where ((`test`.`t3i`.`c1` = `materiali
 zed subselect`.`b1`) and (`test`.`t3i`.`c2` = `materialized subselect`.`b2`))))) ), <primary_index_lookup>(`test`.`t1i`.`a1` in <temporary table> on distinct_key where ((`test`.`t1i`.`a1` = `materialized subselect`.`c1`) and (`test`.`t1i`.`a2` = `materialized subselect`.`c2`)))))))
 (select * from t1
 where (a1, a2) in (select b1, b2 from t2
 where b2 in (select c2 from t3 where c2 LIKE '%02') or
@@ -407,7 +407,7 @@ id	select_type	table	type	possible_keys
 3	DEPENDENT UNION	t2	ALL	NULL	NULL	NULL	NULL	5	100.00	Using where
 NULL	UNION RESULT	<union2,3>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
 Warnings:
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where ((`test`.`t1`.`a1` > '0') and (<cache>(`test`.`t1`.`a1`) = `test`.`t1`.`a1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t1`.`a2`)) union select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where ((`test`.`t2`.`b1` < '9') and (<cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`)))) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t3` where <in_optimizer>((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <p
 rimary_index_lookup>(`test`.`t3`.`c1` in <temporary table> on distinct_key))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key))))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where ((`test`.`t1`.`a1` > '0') and (<cache>(`test`.`t1`.`a1`) = `test`.`t1`.`a1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t1`.`a2`)) union select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where ((`test`.`t2`.`b1` < '9') and (<cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`)))) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(`test`.`t1`.`a1`,`test`.`t1`.`a2`) in ( <materialize> (select `test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t3` where <in_optimizer>((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( <materialize> (select `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <p
 rimary_index_lookup>(`test`.`t3`.`c1` in <temporary table> on distinct_key where ((`test`.`t3`.`c1` = `materialized subselect`.`b1`) and (`test`.`t3`.`c2` = `materialized subselect`.`b2`))))) ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `materialized subselect`.`c1`) and (`test`.`t1`.`a2` = `materialized subselect`.`c2`))))))
 select * from t1
 where (a1, a2) in (select * from t1 where a1 > '0' UNION select * from t2 where b1 < '9') and
 (a1, a2) in (select c1, c2 from t3
@@ -430,7 +430,7 @@ id	select_type	table	type	possible_keys
 3	DEPENDENT UNION	t2	ALL	NULL	NULL	NULL	NULL	5	100.00	Using where
 NULL	UNION RESULT	<union2,3>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
 Warnings:
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2`,`test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t1` join `test`.`t3` where ((`test`.`t3`.`c1` = `test`.`t1`.`a1`) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where ((`test`.`t1`.`a1` > '0') and (<cache>(`test`.`t1`.`a1`) = `test`.`t1`.`a1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t1`.`a2`)) union select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where ((`test`.`t2`.`b1` < '9') and (<cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`)))) and <in_optimizer>((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( <materialize> (select `test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t3` where <in_optimizer>((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( <materialize> (selec
 t `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3`.`c1` in <temporary table> on distinct_key))) ), <primary_index_lookup>(`test`.`t3`.`c1` in <temporary table> on distinct_key))))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2`,`test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t1` join `test`.`t3` where ((`test`.`t3`.`c1` = `test`.`t1`.`a1`) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where ((`test`.`t1`.`a1` > '0') and (<cache>(`test`.`t1`.`a1`) = `test`.`t1`.`a1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t1`.`a2`)) union select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where ((`test`.`t2`.`b1` < '9') and (<cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`)))) and <in_optimizer>((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( <materialize> (select `test`.`t3`.`c1` AS `c1`,`test`.`t3`.`c2` AS `c2` from `test`.`t3` where <in_optimizer>((`test`.`t3`.`c1`,`test`.`t3`.`c2`),(`test`.`t3`.`c1`,`test`.`t3`.`c2`) in ( <materialize> (selec
 t `test`.`t2i`.`b1` AS `b1`,`test`.`t2i`.`b2` AS `b2` from `test`.`t2i` where (`test`.`t2i`.`b2` > '0') ), <primary_index_lookup>(`test`.`t3`.`c1` in <temporary table> on distinct_key where ((`test`.`t3`.`c1` = `materialized subselect`.`b1`) and (`test`.`t3`.`c2` = `materialized subselect`.`b2`))))) ), <primary_index_lookup>(`test`.`t3`.`c1` in <temporary table> on distinct_key where ((`test`.`t3`.`c1` = `materialized subselect`.`c1`) and (`test`.`t3`.`c2` = `materialized subselect`.`c2`))))))
 select * from t1, t3
 where (a1, a2) in (select * from t1 where a1 > '0' UNION select * from t2 where b1 < '9') and
 (c1, c2) in (select c1, c2 from t3
@@ -476,7 +476,7 @@ id	select_type	table	type	possible_keys
 Warnings:
 Note	1276	Field or reference 'test.t1.a1' of SELECT #3 was resolved in SELECT #1
 Note	1276	Field or reference 'test.t1.a2' of SELECT #6 was resolved in SELECT #1
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where ((<in_optimizer>(`test`.`t2`.`b2`,<exists>(select 1 AS `Not_used` from `test`.`t3` `t3a` where ((`test`.`t3a`.`c1` = `test`.`t1`.`a1`) and (<cache>(`test`.`t2`.`b2`) = `test`.`t3a`.`c2`)))) or <in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (select `test`.`t3b`.`c2` AS `c2` from `test`.`t3` `t3b` where (`test`.`t3b`.`c2` like '%03') ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key)))) and (<cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`)))) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(select `test`.`t3c`.`c1` AS `c1`,`test`.`t3c`.`c2` AS `c2` from `test`.`t3` `t3c` where (<in_optimizer>((`test`.`t3c`.`c1`,`test`.`t3c`.`c2`),<exists>
 (<index_lookup>(<cache>(`test`.`t3c`.`c1`) in t2i on it2i3 where (((`test`.`t2i`.`b2` > '0') or (`test`.`t2i`.`b2` = `test`.`t1`.`a2`)) and (<cache>(`test`.`t3c`.`c1`) = `test`.`t2i`.`b1`) and (<cache>(`test`.`t3c`.`c2`) = `test`.`t2i`.`b2`))))) and (<cache>(`test`.`t1`.`a1`) = `test`.`t3c`.`c1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t3c`.`c2`)))))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (<in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(select `test`.`t2`.`b1` AS `b1`,`test`.`t2`.`b2` AS `b2` from `test`.`t2` where ((<in_optimizer>(`test`.`t2`.`b2`,<exists>(select 1 AS `Not_used` from `test`.`t3` `t3a` where ((`test`.`t3a`.`c1` = `test`.`t1`.`a1`) and (<cache>(`test`.`t2`.`b2`) = `test`.`t3a`.`c2`)))) or <in_optimizer>(`test`.`t2`.`b2`,`test`.`t2`.`b2` in ( <materialize> (select `test`.`t3b`.`c2` AS `c2` from `test`.`t3` `t3b` where (`test`.`t3b`.`c2` like '%03') ), <primary_index_lookup>(`test`.`t2`.`b2` in <temporary table> on distinct_key where ((`test`.`t2`.`b2` = `materialized subselect`.`c2`)))))) and (<cache>(`test`.`t1`.`a1`) = `test`.`t2`.`b1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t2`.`b2`)))) and <in_optimizer>((`test`.`t1`.`a1`,`test`.`t1`.`a2`),<exists>(select `test`.`t3c`.`c1` AS `c1`,`test`.`t3c`.`c2` AS `c2` from `test`.`t3` `t3c` where (<i
 n_optimizer>((`test`.`t3c`.`c1`,`test`.`t3c`.`c2`),<exists>(<index_lookup>(<cache>(`test`.`t3c`.`c1`) in t2i on it2i3 where (((`test`.`t2i`.`b2` > '0') or (`test`.`t2i`.`b2` = `test`.`t1`.`a2`)) and (<cache>(`test`.`t3c`.`c1`) = `test`.`t2i`.`b1`) and (<cache>(`test`.`t3c`.`c2`) = `test`.`t2i`.`b2`))))) and (<cache>(`test`.`t1`.`a1`) = `test`.`t3c`.`c1`) and (<cache>(`test`.`t1`.`a2`) = `test`.`t3c`.`c2`)))))
 explain extended
 select * from t1 where (a1, a2) in (select '1 - 01', '2 - 01');
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
@@ -611,7 +611,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1_16	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2_16	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 Warnings:
-Note	1003	select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` where <in_optimizer>(`test`.`t1_16`.`a1`,`test`.`t1_16`.`a1` in ( <materialize> (select substr(`test`.`t2_16`.`b1`,1,16) AS `substring(b1,1,16)` from `test`.`t2_16` where (`test`.`t2_16`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1_16`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` where <in_optimizer>(`test`.`t1_16`.`a1`,`test`.`t1_16`.`a1` in ( <materialize> (select substr(`test`.`t2_16`.`b1`,1,16) AS `substring(b1,1,16)` from `test`.`t2_16` where (`test`.`t2_16`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1_16`.`a1` in <temporary table> on distinct_key where ((`test`.`t1_16`.`a1` = `materialized subselect`.`substring(b1,1,16)`)))))
 select left(a1,7), left(a2,7)
 from t1_16
 where a1 in (select substring(b1,1,16) from t2_16 where b1 > '0');
@@ -640,7 +640,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1_16	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2_16	ALL	NULL	NULL	NULL	NULL	3	100.00	Using filesort
 Warnings:
-Note	1003	select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` where <in_optimizer>(`test`.`t1_16`.`a1`,`test`.`t1_16`.`a1` in ( <materialize> (select group_concat(`test`.`t2_16`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_16` group by `test`.`t2_16`.`b2` ), <primary_index_lookup>(`test`.`t1_16`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` where <in_optimizer>(`test`.`t1_16`.`a1`,`test`.`t1_16`.`a1` in ( <materialize> (select group_concat(`test`.`t2_16`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_16` group by `test`.`t2_16`.`b2` ), <primary_index_lookup>(`test`.`t1_16`.`a1` in <temporary table> on distinct_key where ((`test`.`t1_16`.`a1` = `materialized subselect`.`group_concat(b1)`)))))
 select left(a1,7), left(a2,7)
 from t1_16
 where a1 in (select group_concat(b1) from t2_16 group by b2);
@@ -657,12 +657,12 @@ where t2.b2 = substring(t2_16.b2,1,6) an
 t2.b1 IN (select c1 from t3 where c2 > '0')));
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
-2	SUBQUERY	t1_16	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
+2	DEPENDENT SUBQUERY	t1_16	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 3	DEPENDENT SUBQUERY	t2_16	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 3	DEPENDENT SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	5	100.00	Using where; Using join buffer
 4	SUBQUERY	t3	ALL	NULL	NULL	NULL	NULL	4	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>(concat(`test`.`t1`.`a1`,'x'),concat(`test`.`t1`.`a1`,'x') in ( <materialize> (select left(`test`.`t1_16`.`a1`,8) AS `left(a1,8)` from `test`.`t1_16` where <in_optimizer>((`test`.`t1_16`.`a1`,`test`.`t1_16`.`a2`),(`test`.`t1_16`.`a1`,`test`.`t1_16`.`a2`) in (select `test`.`t2_16`.`b1` AS `b1`,`test`.`t2_16`.`b2` AS `b2` from `test`.`t2_16` join `test`.`t2` where ((`test`.`t2`.`b2` = substr(`test`.`t2_16`.`b2`,1,6)) and <in_optimizer>(`test`.`t2`.`b1`,`test`.`t2`.`b1` in ( <materialize> (select `test`.`t3`.`c1` AS `c1` from `test`.`t3` where (`test`.`t3`.`c2` > '0') ), <primary_index_lookup>(`test`.`t2`.`b1` in <temporary table> on distinct_key))) and (<cache>(`test`.`t1_16`.`a1`) = `test`.`t2_16`.`b1`) and (<cache>(`test`.`t1_16`.`a2`) = `test`.`t2_16`.`b2`)))) ), <primary_index_lookup>(concat(`test`.`t1`.`a1`,'x') in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <in_optimizer>(concat(`test`.`t1`.`a1`,'x'),<exists>(select 1 AS `Not_used` from `test`.`t1_16` where (<in_optimizer>((`test`.`t1_16`.`a1`,`test`.`t1_16`.`a2`),(`test`.`t1_16`.`a1`,`test`.`t1_16`.`a2`) in (select `test`.`t2_16`.`b1` AS `b1`,`test`.`t2_16`.`b2` AS `b2` from `test`.`t2_16` join `test`.`t2` where ((`test`.`t2`.`b2` = substr(`test`.`t2_16`.`b2`,1,6)) and <in_optimizer>(`test`.`t2`.`b1`,`test`.`t2`.`b1` in ( <materialize> (select `test`.`t3`.`c1` AS `c1` from `test`.`t3` where (`test`.`t3`.`c2` > '0') ), <primary_index_lookup>(`test`.`t2`.`b1` in <temporary table> on distinct_key where ((`test`.`t2`.`b1` = `materialized subselect`.`c1`))))) and (<cache>(`test`.`t1_16`.`a1`) = `test`.`t2_16`.`b1`) and (<cache>(`test`.`t1_16`.`a2`) = `test`.`t2_16`.`b2`)))) and (<cache>(concat(`test`.`t1`.`a1`,'x')) = left(`test`.`t1_16`.`a1`,8)))))
 drop table t1_16, t2_16, t3_16;
 set @blob_len = 512;
 set @suffix_len = @blob_len - @prefix_len;
@@ -724,7 +724,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1_512	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2_512	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 Warnings:
-Note	1003	select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` where <in_optimizer>(`test`.`t1_512`.`a1`,`test`.`t1_512`.`a1` in ( <materialize> (select substr(`test`.`t2_512`.`b1`,1,512) AS `substring(b1,1,512)` from `test`.`t2_512` where (`test`.`t2_512`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1_512`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` where <in_optimizer>(`test`.`t1_512`.`a1`,`test`.`t1_512`.`a1` in ( <materialize> (select substr(`test`.`t2_512`.`b1`,1,512) AS `substring(b1,1,512)` from `test`.`t2_512` where (`test`.`t2_512`.`b1` > '0') ), <primary_index_lookup>(`test`.`t1_512`.`a1` in <temporary table> on distinct_key where ((`test`.`t1_512`.`a1` = `materialized subselect`.`substring(b1,1,512)`)))))
 select left(a1,7), left(a2,7)
 from t1_512
 where a1 in (select substring(b1,1,512) from t2_512 where b1 > '0');
@@ -738,13 +738,11 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1_512	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2_512	ALL	NULL	NULL	NULL	NULL	3	100.00	Using filesort
 Warnings:
-Note	1003	select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` where <in_optimizer>(`test`.`t1_512`.`a1`,`test`.`t1_512`.`a1` in ( <materialize> (select group_concat(`test`.`t2_512`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_512` group by `test`.`t2_512`.`b2` ), <primary_index_lookup>(`test`.`t1_512`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` where <in_optimizer>(`test`.`t1_512`.`a1`,`test`.`t1_512`.`a1` in ( <materialize> (select group_concat(`test`.`t2_512`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_512` group by `test`.`t2_512`.`b2` ), <primary_index_lookup>(`test`.`t1_512`.`a1` in <temporary table> on distinct_key where ((`test`.`t1_512`.`a1` = `materialized subselect`.`group_concat(b1)`)))))
 select left(a1,7), left(a2,7)
 from t1_512
 where a1 in (select group_concat(b1) from t2_512 group by b2);
 left(a1,7)	left(a2,7)
-1 - 01x	2 - 01x
-1 - 02x	2 - 02x
 set @@group_concat_max_len = 256;
 explain extended select left(a1,7), left(a2,7)
 from t1_512
@@ -753,13 +751,11 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1_512	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2_512	ALL	NULL	NULL	NULL	NULL	3	100.00	Using filesort
 Warnings:
-Note	1003	select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` where <in_optimizer>(`test`.`t1_512`.`a1`,`test`.`t1_512`.`a1` in ( <materialize> (select group_concat(`test`.`t2_512`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_512` group by `test`.`t2_512`.`b2` ), <primary_index_lookup>(`test`.`t1_512`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select left(`test`.`t1_512`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_512`.`a2`,7) AS `left(a2,7)` from `test`.`t1_512` where <in_optimizer>(`test`.`t1_512`.`a1`,`test`.`t1_512`.`a1` in ( <materialize> (select group_concat(`test`.`t2_512`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_512` group by `test`.`t2_512`.`b2` ), <primary_index_lookup>(`test`.`t1_512`.`a1` in <temporary table> on distinct_key where ((`test`.`t1_512`.`a1` = `materialized subselect`.`group_concat(b1)`)))))
 select left(a1,7), left(a2,7)
 from t1_512
 where a1 in (select group_concat(b1) from t2_512 group by b2);
 left(a1,7)	left(a2,7)
-1 - 01x	2 - 01x
-1 - 02x	2 - 02x
 drop table t1_512, t2_512, t3_512;
 set @blob_len = 1024;
 set @suffix_len = @blob_len - @prefix_len;
@@ -835,13 +831,11 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1_1024	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2_1024	ALL	NULL	NULL	NULL	NULL	3	100.00	Using filesort
 Warnings:
-Note	1003	select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1024` where <in_optimizer>(`test`.`t1_1024`.`a1`,`test`.`t1_1024`.`a1` in ( <materialize> (select group_concat(`test`.`t2_1024`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_1024` group by `test`.`t2_1024`.`b2` ), <primary_index_lookup>(`test`.`t1_1024`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1024` where <in_optimizer>(`test`.`t1_1024`.`a1`,`test`.`t1_1024`.`a1` in ( <materialize> (select group_concat(`test`.`t2_1024`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_1024` group by `test`.`t2_1024`.`b2` ), <primary_index_lookup>(`test`.`t1_1024`.`a1` in <temporary table> on distinct_key where ((`test`.`t1_1024`.`a1` = `materialized subselect`.`group_concat(b1)`)))))
 select left(a1,7), left(a2,7)
 from t1_1024
 where a1 in (select group_concat(b1) from t2_1024 group by b2);
 left(a1,7)	left(a2,7)
-1 - 01x	2 - 01x
-1 - 02x	2 - 02x
 set @@group_concat_max_len = 256;
 explain extended select left(a1,7), left(a2,7)
 from t1_1024
@@ -850,13 +844,11 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1_1024	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2_1024	ALL	NULL	NULL	NULL	NULL	3	100.00	Using filesort
 Warnings:
-Note	1003	select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1024` where <in_optimizer>(`test`.`t1_1024`.`a1`,`test`.`t1_1024`.`a1` in ( <materialize> (select group_concat(`test`.`t2_1024`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_1024` group by `test`.`t2_1024`.`b2` ), <primary_index_lookup>(`test`.`t1_1024`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select left(`test`.`t1_1024`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1024`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1024` where <in_optimizer>(`test`.`t1_1024`.`a1`,`test`.`t1_1024`.`a1` in ( <materialize> (select group_concat(`test`.`t2_1024`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_1024` group by `test`.`t2_1024`.`b2` ), <primary_index_lookup>(`test`.`t1_1024`.`a1` in <temporary table> on distinct_key where ((`test`.`t1_1024`.`a1` = `materialized subselect`.`group_concat(b1)`)))))
 select left(a1,7), left(a2,7)
 from t1_1024
 where a1 in (select group_concat(b1) from t2_1024 group by b2);
 left(a1,7)	left(a2,7)
-1 - 01x	2 - 01x
-1 - 02x	2 - 02x
 drop table t1_1024, t2_1024, t3_1024;
 set @blob_len = 1025;
 set @suffix_len = @blob_len - @prefix_len;
@@ -932,13 +924,11 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1_1025	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2_1025	ALL	NULL	NULL	NULL	NULL	3	100.00	Using filesort
 Warnings:
-Note	1003	select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1025` where <in_optimizer>(`test`.`t1_1025`.`a1`,`test`.`t1_1025`.`a1` in ( <materialize> (select group_concat(`test`.`t2_1025`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_1025` group by `test`.`t2_1025`.`b2` ), <primary_index_lookup>(`test`.`t1_1025`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1025` where <in_optimizer>(`test`.`t1_1025`.`a1`,`test`.`t1_1025`.`a1` in ( <materialize> (select group_concat(`test`.`t2_1025`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_1025` group by `test`.`t2_1025`.`b2` ), <primary_index_lookup>(`test`.`t1_1025`.`a1` in <temporary table> on distinct_key where ((`test`.`t1_1025`.`a1` = `materialized subselect`.`group_concat(b1)`)))))
 select left(a1,7), left(a2,7)
 from t1_1025
 where a1 in (select group_concat(b1) from t2_1025 group by b2);
 left(a1,7)	left(a2,7)
-1 - 01x	2 - 01x
-1 - 02x	2 - 02x
 set @@group_concat_max_len = 256;
 explain extended select left(a1,7), left(a2,7)
 from t1_1025
@@ -947,13 +937,11 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1_1025	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2_1025	ALL	NULL	NULL	NULL	NULL	3	100.00	Using filesort
 Warnings:
-Note	1003	select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1025` where <in_optimizer>(`test`.`t1_1025`.`a1`,`test`.`t1_1025`.`a1` in ( <materialize> (select group_concat(`test`.`t2_1025`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_1025` group by `test`.`t2_1025`.`b2` ), <primary_index_lookup>(`test`.`t1_1025`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select left(`test`.`t1_1025`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_1025`.`a2`,7) AS `left(a2,7)` from `test`.`t1_1025` where <in_optimizer>(`test`.`t1_1025`.`a1`,`test`.`t1_1025`.`a1` in ( <materialize> (select group_concat(`test`.`t2_1025`.`b1` separator ',') AS `group_concat(b1)` from `test`.`t2_1025` group by `test`.`t2_1025`.`b2` ), <primary_index_lookup>(`test`.`t1_1025`.`a1` in <temporary table> on distinct_key where ((`test`.`t1_1025`.`a1` = `materialized subselect`.`group_concat(b1)`)))))
 select left(a1,7), left(a2,7)
 from t1_1025
 where a1 in (select group_concat(b1) from t2_1025 group by b2);
 left(a1,7)	left(a2,7)
-1 - 01x	2 - 01x
-1 - 02x	2 - 02x
 drop table t1_1025, t2_1025, t3_1025;
 create table t1bit (a1 bit(3), a2 bit(3));
 create table t2bit (b1 bit(3), b2 bit(3));
@@ -971,7 +959,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1bit	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
 2	SUBQUERY	t2bit	ALL	NULL	NULL	NULL	NULL	3	100.00	
 Warnings:
-Note	1003	select conv(`test`.`t1bit`.`a1`,10,2) AS `bin(a1)`,conv(`test`.`t1bit`.`a2`,10,2) AS `bin(a2)` from `test`.`t1bit` where <in_optimizer>((`test`.`t1bit`.`a1`,`test`.`t1bit`.`a2`),(`test`.`t1bit`.`a1`,`test`.`t1bit`.`a2`) in ( <materialize> (select `test`.`t2bit`.`b1` AS `b1`,`test`.`t2bit`.`b2` AS `b2` from `test`.`t2bit` ), <primary_index_lookup>(`test`.`t1bit`.`a1` in <temporary table> on distinct_key)))
+Note	1003	select conv(`test`.`t1bit`.`a1`,10,2) AS `bin(a1)`,conv(`test`.`t1bit`.`a2`,10,2) AS `bin(a2)` from `test`.`t1bit` where <in_optimizer>((`test`.`t1bit`.`a1`,`test`.`t1bit`.`a2`),(`test`.`t1bit`.`a1`,`test`.`t1bit`.`a2`) in ( <materialize> (select `test`.`t2bit`.`b1` AS `b1`,`test`.`t2bit`.`b2` AS `b2` from `test`.`t2bit` ), <primary_index_lookup>(`test`.`t1bit`.`a1` in <temporary table> on distinct_key where ((`test`.`t1bit`.`a1` = `materialized subselect`.`b1`) and (`test`.`t1bit`.`a2` = `materialized subselect`.`b2`)))))
 select bin(a1), bin(a2)
 from t1bit
 where (a1, a2) in (select b1, b2 from t2bit);
@@ -1042,7 +1030,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	7	100.00	Using where
 2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	6	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (select `test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (select `test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`c`)))))
 select a from t1 where a in (select c from t2 where d >= 20);
 a
 2
@@ -1056,7 +1044,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	index	NULL	it1a	4	NULL	7	100.00	Using where; Using index
 2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	6	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (select `test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (select `test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`c`)))))
 select a from t1 where a in (select c from t2 where d >= 20);
 a
 2
@@ -1070,7 +1058,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	index	NULL	it1a	4	NULL	7	100.00	Using where; Using index
 2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	7	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (select `test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (select `test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`c`)))))
 select a from t1 where a in (select c from t2 where d >= 20);
 a
 2
@@ -1083,7 +1071,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	index	NULL	it1a	4	NULL	7	100.00	Using index
 2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	7	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a` having <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (select `test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a` having <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (select `test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`c`)))))
 select a from t1 group by a having a in (select c from t2 where d >= 20);
 a
 2
@@ -1095,7 +1083,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	index	NULL	it1a	4	NULL	7	100.00	Using index
 2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	7	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a` having <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (select `test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t1`.`a` AS `a` from `test`.`t1` group by `test`.`t1`.`a` having <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in ( <materialize> (select `test`.`t2`.`c` AS `c` from `test`.`t2` where (`test`.`t2`.`d` >= 20) ), <primary_index_lookup>(`test`.`t1`.`a` in <temporary table> on distinct_key where ((`test`.`t1`.`a` = `materialized subselect`.`c`)))))
 select a from t1 group by a having a in (select c from t2 where d >= 20);
 a
 2
@@ -1145,3 +1133,50 @@ t2.a = 3 and not t2.a not in (select t2.
 1
 1
 drop table t2;
+create table t1 (a1 int key);
+create table t2 (b1 int);
+insert into t1 values (5);
+explain select min(a1) from t1 where 7 in (select b1 from t2 group by b1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Select tables optimized away
+2	SUBQUERY	t2	system	NULL	NULL	NULL	NULL	0	const row not found
+select min(a1) from t1 where 7 in (select b1 from t2 group by b1);
+min(a1)
+set @@optimizer_switch='no_materialization';
+explain select min(a1) from t1 where 7 in (select b1 from t2 group by b1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Select tables optimized away
+2	DEPENDENT SUBQUERY	t2	system	NULL	NULL	NULL	NULL	0	const row not found
+select min(a1) from t1 where 7 in (select b1 from t2 group by b1);
+min(a1)
+set @@optimizer_switch='no_semijoin';
+explain select min(a1) from t1 where 7 in (select b1 from t2);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Select tables optimized away
+2	SUBQUERY	t2	system	NULL	NULL	NULL	NULL	0	const row not found
+select min(a1) from t1 where 7 in (select b1 from t2);
+min(a1)
+set @@optimizer_switch='no_materialization';
+explain select min(a1) from t1 where 7 in (select b1 from t2);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const tables
+select min(a1) from t1 where 7 in (select b1 from t2);
+min(a1)
+NULL
+drop table t1,t2;
+create table t1 (a char(2), b varchar(10));
+insert into t1 values ('a',  'aaa');
+insert into t1 values ('aa', 'aaaa');
+set @@optimizer_switch='no_semijoin';
+explain select a,b from t1 where b in (select a from t1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	
+select a,b from t1 where b in (select a from t1);
+a	b
+prepare st1 from "select a,b from t1 where b in (select a from t1)";
+execute st1;
+a	b
+execute st1;
+a	b
+drop table t1;

=== modified file 'mysql-test/r/subselect_no_mat.result'
--- a/mysql-test/r/subselect_no_mat.result	2008-12-13 11:02:16 +0000
+++ b/mysql-test/r/subselect_no_mat.result	2008-12-13 20:01:27 +0000
@@ -1360,11 +1360,11 @@ a
 3
 explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	PRIMARY	t2	index	a	a	5	NULL	4	100.00	Using index; Start temporary
-1	PRIMARY	t1	ref	a	a	5	test.t2.a	101	100.00	Using index
-1	PRIMARY	t3	index	a	a	5	NULL	3	100.00	Using where; Using index; End temporary; Using join buffer
+1	PRIMARY	t2	index	a	a	5	NULL	4	100.00	Using index
+1	PRIMARY	t3	index	a	a	5	NULL	3	100.00	Using index
+1	PRIMARY	t1	ref	a	a	10	test.t2.a,test.t3.a	116	100.00	Using index; FirstMatch(t2)
 Warnings:
-Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1` join `test`.`t3`) where ((`test`.`t1`.`a` = `test`.`t2`.`a`) and (`test`.`t3`.`a` = `test`.`t1`.`b`))
+Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` semi join (`test`.`t1` join `test`.`t3`) where ((`test`.`t1`.`a` = `test`.`t2`.`a`) and (`test`.`t1`.`b` = `test`.`t3`.`a`))
 insert into t1 values (3,31);
 select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
 a
@@ -2822,8 +2822,8 @@ Warnings:
 Note	1003	select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<in_optimizer>((`test`.`t1`.`one`,`test`.`t1`.`two`),<exists>(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where ((`test`.`t2`.`flag` = '0') and trigcond(((<cache>(`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond(((<cache>(`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`)))) having (trigcond(<is_not_null_test>(`test`.`t2`.`one`)) and trigcond(<is_not_null_test>(`test`.`t2`.`two`))))) AS `test` from `test`.`t1`
 explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N');
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	8	100.00	Start temporary
-1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	9	100.00	Using where; End temporary; Using join buffer
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	8	100.00	
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	9	100.00	Using where; FirstMatch(t1)
 Warnings:
 Note	1003	select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`two` = `test`.`t1`.`two`) and (`test`.`t2`.`one` = `test`.`t1`.`one`) and (`test`.`t2`.`flag` = 'N'))
 explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1;
@@ -3411,7 +3411,7 @@ EXPLAIN
 SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	9	Using where
-2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	9	Using temporary; Using filesort
+2	DEPENDENT SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	9	Using temporary; Using filesort
 ALTER TABLE t1 ADD INDEX(a);
 SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a);
 a	b
@@ -3422,7 +3422,7 @@ EXPLAIN
 SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	9	Using where
-2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	9	Using temporary; Using filesort
+2	DEPENDENT SUBQUERY	t1	index	NULL	a	8	NULL	1	Using filesort
 DROP TABLE t1;
 create table t1( f1 int,f2 int);
 insert into t1 values (1,1),(2,2);
@@ -4368,16 +4368,16 @@ CREATE TABLE t1 (a INT);
 INSERT INTO t1 VALUES (1),(2);
 EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 GROUP BY a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where
-2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using temporary; Using filesort
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	
+2	DEPENDENT SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using temporary; Using filesort
 Warnings:
-Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,1 in ( <materialize> (select 1 AS `1` from `test`.`t1` group by `test`.`t1`.`a` ), <primary_index_lookup>(1 in <temporary table> on distinct_key)))
+Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,<exists>(select 1 AS `1` from `test`.`t1` group by `test`.`t1`.`a` having (<cache>(1) = <ref_null_helper>(1))))
 EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where
-2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where; Using temporary; Using filesort
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const tables
+2	DEPENDENT SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where; Using temporary; Using filesort
 Warnings:
-Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,1 in ( <materialize> (select 1 AS `1` from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` ), <primary_index_lookup>(1 in <temporary table> on distinct_key)))
+Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,<exists>(select 1 AS `1` from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` having (<cache>(1) = <ref_null_helper>(1))))
 DROP TABLE t1;
 End of 5.0 tests.
 create table t_out (subcase char(3),

=== modified file 'mysql-test/r/subselect_no_opts.result'
--- a/mysql-test/r/subselect_no_opts.result	2008-12-13 11:02:16 +0000
+++ b/mysql-test/r/subselect_no_opts.result	2008-12-13 20:01:27 +0000
@@ -2822,10 +2822,10 @@ Warnings:
 Note	1003	select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<in_optimizer>((`test`.`t1`.`one`,`test`.`t1`.`two`),<exists>(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where ((`test`.`t2`.`flag` = '0') and trigcond(((<cache>(`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond(((<cache>(`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`)))) having (trigcond(<is_not_null_test>(`test`.`t2`.`one`)) and trigcond(<is_not_null_test>(`test`.`t2`.`two`))))) AS `test` from `test`.`t1`
 explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N');
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	8	100.00	Start temporary
-1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	9	100.00	Using where; End temporary; Using join buffer
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	8	100.00	Using where
+2	DEPENDENT SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	9	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`two` = `test`.`t1`.`two`) and (`test`.`t2`.`one` = `test`.`t1`.`one`) and (`test`.`t2`.`flag` = 'N'))
+Note	1003	select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`one`,`test`.`t1`.`two`),<exists>(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where ((`test`.`t2`.`flag` = 'N') and (<cache>(`test`.`t1`.`one`) = `test`.`t2`.`one`) and (<cache>(`test`.`t1`.`two`) = `test`.`t2`.`two`))))
 explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	8	100.00	
@@ -3411,7 +3411,7 @@ EXPLAIN
 SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	9	Using where
-2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	9	Using temporary; Using filesort
+2	DEPENDENT SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	9	Using temporary; Using filesort
 ALTER TABLE t1 ADD INDEX(a);
 SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a);
 a	b
@@ -3422,7 +3422,7 @@ EXPLAIN
 SELECT * FROM t1 WHERE (a,b) = ANY (SELECT a, max(b) FROM t1 GROUP BY a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	9	Using where
-2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	9	Using temporary; Using filesort
+2	DEPENDENT SUBQUERY	t1	index	NULL	a	8	NULL	1	Using filesort
 DROP TABLE t1;
 create table t1( f1 int,f2 int);
 insert into t1 values (1,1),(2,2);
@@ -4219,8 +4219,8 @@ CREATE INDEX I1 ON t1 (a);
 CREATE INDEX I2 ON t1 (b);
 EXPLAIN SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t1	index	I1	I1	2	NULL	2	Using index; LooseScan
-1	PRIMARY	t1	ref	I2	I2	13	test.t1.a	2	Using index condition
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	DEPENDENT SUBQUERY	t1	index_subquery	I1	I1	2	func	2	Using index; Using where
 SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1);
 a	b
 CREATE TABLE t2 (a VARCHAR(1), b VARCHAR(10));
@@ -4229,15 +4229,15 @@ CREATE INDEX I1 ON t2 (a);
 CREATE INDEX I2 ON t2 (b);
 EXPLAIN SELECT a,b FROM t2 WHERE b IN (SELECT a FROM t2);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t2	index	I1	I1	4	NULL	2	Using index; LooseScan
-1	PRIMARY	t2	ref	I2	I2	13	test.t2.a	2	Using index condition
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	DEPENDENT SUBQUERY	t2	index_subquery	I1	I1	4	func	2	Using index; Using where
 SELECT a,b FROM t2 WHERE b IN (SELECT a FROM t2);
 a	b
 EXPLAIN
 SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t1	index	I1	I1	2	NULL	2	Using where; Using index; LooseScan
-1	PRIMARY	t1	ref	I2	I2	13	test.t1.a	2	Using index condition
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	DEPENDENT SUBQUERY	t1	index_subquery	I1	I1	2	func	2	Using index; Using where
 SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500);
 a	b
 DROP TABLE t1,t2;
@@ -4368,16 +4368,16 @@ CREATE TABLE t1 (a INT);
 INSERT INTO t1 VALUES (1),(2);
 EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 GROUP BY a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where
-2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using temporary; Using filesort
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	
+2	DEPENDENT SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using temporary; Using filesort
 Warnings:
-Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,1 in ( <materialize> (select 1 AS `1` from `test`.`t1` group by `test`.`t1`.`a` ), <primary_index_lookup>(1 in <temporary table> on distinct_key)))
+Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,<exists>(select 1 AS `1` from `test`.`t1` group by `test`.`t1`.`a` having (<cache>(1) = <ref_null_helper>(1))))
 EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where
-2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where; Using temporary; Using filesort
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const tables
+2	DEPENDENT SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where; Using temporary; Using filesort
 Warnings:
-Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,1 in ( <materialize> (select 1 AS `1` from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` ), <primary_index_lookup>(1 in <temporary table> on distinct_key)))
+Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,<exists>(select 1 AS `1` from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` having (<cache>(1) = <ref_null_helper>(1))))
 DROP TABLE t1;
 End of 5.0 tests.
 create table t_out (subcase char(3),

=== modified file 'mysql-test/r/subselect_no_semijoin.result'
--- a/mysql-test/r/subselect_no_semijoin.result	2008-12-13 11:02:16 +0000
+++ b/mysql-test/r/subselect_no_semijoin.result	2008-12-13 20:01:27 +0000
@@ -1300,7 +1300,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t2	index	NULL	PRIMARY	4	NULL	4	100.00	Using where; Using index
 2	SUBQUERY	t1	index	NULL	PRIMARY	4	NULL	4	100.00	Using index
 Warnings:
-Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where ((`test`.`t2`.`a` = `materialized subselect`.`a`)))))
 select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
 a
 2
@@ -1310,7 +1310,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t2	index	NULL	PRIMARY	4	NULL	4	100.00	Using where; Using index
 2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	4	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`b` <> 30) ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`b` <> 30) ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where ((`test`.`t2`.`a` = `materialized subselect`.`a`)))))
 select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
 a
 2
@@ -1321,7 +1321,7 @@ id	select_type	table	type	possible_keys
 2	SUBQUERY	t3	index	PRIMARY	PRIMARY	4	NULL	3	100.00	Using index
 2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	4	100.00	Using where; Using join buffer
 Warnings:
-Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` join `test`.`t3` where (`test`.`t1`.`b` = `test`.`t3`.`a`) ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` join `test`.`t3` where (`test`.`t1`.`b` = `test`.`t3`.`a`) ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where ((`test`.`t2`.`a` = `materialized subselect`.`a`)))))
 drop table t1, t2, t3;
 create table t1 (a int, b int, index a (a,b));
 create table t2 (a int, index a (a));
@@ -1343,7 +1343,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t2	index	NULL	a	5	NULL	4	100.00	Using where; Using index
 2	SUBQUERY	t1	index	NULL	a	10	NULL	10004	100.00	Using index
 Warnings:
-Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where ((`test`.`t2`.`a` = `materialized subselect`.`a`)))))
 select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
 a
 2
@@ -1353,7 +1353,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t2	index	NULL	a	5	NULL	4	100.00	Using where; Using index
 2	SUBQUERY	t1	index	NULL	a	10	NULL	10004	100.00	Using where; Using index
 Warnings:
-Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`b` <> 30) ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`b` <> 30) ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where ((`test`.`t2`.`a` = `materialized subselect`.`a`)))))
 select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
 a
 2
@@ -1364,7 +1364,7 @@ id	select_type	table	type	possible_keys
 2	SUBQUERY	t3	index	a	a	5	NULL	3	100.00	Using index
 2	SUBQUERY	t1	index	NULL	a	10	NULL	10004	100.00	Using where; Using index; Using join buffer
 Warnings:
-Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` join `test`.`t3` where (`test`.`t1`.`b` = `test`.`t3`.`a`) ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` join `test`.`t3` where (`test`.`t1`.`b` = `test`.`t3`.`a`) ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where ((`test`.`t2`.`a` = `materialized subselect`.`a`)))))
 insert into t1 values (3,31);
 select * from t2 where t2.a in (select a from t1 where t1.b <> 30);
 a
@@ -1380,7 +1380,7 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t2	index	NULL	a	5	NULL	4	100.00	Using where; Using index
 2	SUBQUERY	t1	index	NULL	a	10	NULL	10005	100.00	Using where; Using index
 Warnings:
-Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`b` <> 30) ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key)))
+Note	1003	select `test`.`t2`.`a` AS `a` from `test`.`t2` where <in_optimizer>(`test`.`t2`.`a`,`test`.`t2`.`a` in ( <materialize> (select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`b` <> 30) ), <primary_index_lookup>(`test`.`t2`.`a` in <temporary table> on distinct_key where ((`test`.`t2`.`a` = `materialized subselect`.`a`)))))
 drop table t0, t1, t2, t3;
 create table t1 (a int, b int);
 create table t2 (a int, b int);
@@ -2822,10 +2822,10 @@ Warnings:
 Note	1003	select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two`,<in_optimizer>((`test`.`t1`.`one`,`test`.`t1`.`two`),<exists>(select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where ((`test`.`t2`.`flag` = '0') and trigcond(((<cache>(`test`.`t1`.`one`) = `test`.`t2`.`one`) or isnull(`test`.`t2`.`one`))) and trigcond(((<cache>(`test`.`t1`.`two`) = `test`.`t2`.`two`) or isnull(`test`.`t2`.`two`)))) having (trigcond(<is_not_null_test>(`test`.`t2`.`one`)) and trigcond(<is_not_null_test>(`test`.`t2`.`two`))))) AS `test` from `test`.`t1`
 explain extended SELECT one,two from t1 where ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = 'N');
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	8	100.00	Start temporary
-1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	9	100.00	Using where; End temporary; Using join buffer
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	8	100.00	Using where
+2	SUBQUERY	t2	ALL	NULL	NULL	NULL	NULL	9	100.00	Using where
 Warnings:
-Note	1003	select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`two` = `test`.`t1`.`two`) and (`test`.`t2`.`one` = `test`.`t1`.`one`) and (`test`.`t2`.`flag` = 'N'))
+Note	1003	select `test`.`t1`.`one` AS `one`,`test`.`t1`.`two` AS `two` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`one`,`test`.`t1`.`two`),(`test`.`t1`.`one`,`test`.`t1`.`two`) in ( <materialize> (select `test`.`t2`.`one` AS `one`,`test`.`t2`.`two` AS `two` from `test`.`t2` where (`test`.`t2`.`flag` = 'N') ), <primary_index_lookup>(`test`.`t1`.`one` in <temporary table> on distinct_key where ((`test`.`t1`.`one` = `materialized subselect`.`one`) and (`test`.`t1`.`two` = `materialized subselect`.`two`)))))
 explain extended SELECT one,two,ROW(one,two) IN (SELECT one,two FROM t2 WHERE flag = '0' group by one,two) as 'test' from t1;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	8	100.00	
@@ -4219,8 +4219,8 @@ CREATE INDEX I1 ON t1 (a);
 CREATE INDEX I2 ON t1 (b);
 EXPLAIN SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t1	index	I1	I1	2	NULL	2	Using index; LooseScan
-1	PRIMARY	t1	ref	I2	I2	13	test.t1.a	2	Using index condition
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	SUBQUERY	t1	index	NULL	I1	2	NULL	2	Using index
 SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1);
 a	b
 CREATE TABLE t2 (a VARCHAR(1), b VARCHAR(10));
@@ -4229,15 +4229,15 @@ CREATE INDEX I1 ON t2 (a);
 CREATE INDEX I2 ON t2 (b);
 EXPLAIN SELECT a,b FROM t2 WHERE b IN (SELECT a FROM t2);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t2	index	I1	I1	4	NULL	2	Using index; LooseScan
-1	PRIMARY	t2	ref	I2	I2	13	test.t2.a	2	Using index condition
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	SUBQUERY	t2	index	NULL	I1	4	NULL	2	Using index
 SELECT a,b FROM t2 WHERE b IN (SELECT a FROM t2);
 a	b
 EXPLAIN
 SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t1	index	I1	I1	2	NULL	2	Using where; Using index; LooseScan
-1	PRIMARY	t1	ref	I2	I2	13	test.t1.a	2	Using index condition
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	Using where
+2	SUBQUERY	t1	index	NULL	I1	2	NULL	2	Using where; Using index
 SELECT a,b FROM t1 WHERE b IN (SELECT a FROM t1 WHERE LENGTH(a)<500);
 a	b
 DROP TABLE t1,t2;
@@ -4371,13 +4371,13 @@ id	select_type	table	type	possible_keys
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where
 2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using temporary; Using filesort
 Warnings:
-Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,1 in ( <materialize> (select 1 AS `1` from `test`.`t1` group by `test`.`t1`.`a` ), <primary_index_lookup>(1 in <temporary table> on distinct_key)))
+Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,1 in ( <materialize> (select 1 AS `1` from `test`.`t1` group by `test`.`t1`.`a` ), <primary_index_lookup>(1 in <temporary table> on distinct_key where ((1 = `materialized subselect`.`1`)))))
 EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1 IN (SELECT 1 FROM t1 WHERE a > 3 GROUP BY a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where
 2	SUBQUERY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	Using where; Using temporary; Using filesort
 Warnings:
-Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,1 in ( <materialize> (select 1 AS `1` from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` ), <primary_index_lookup>(1 in <temporary table> on distinct_key)))
+Note	1003	select 1 AS `1` from `test`.`t1` where <in_optimizer>(1,1 in ( <materialize> (select 1 AS `1` from `test`.`t1` where (`test`.`t1`.`a` > 3) group by `test`.`t1`.`a` ), <primary_index_lookup>(1 in <temporary table> on distinct_key where ((1 = `materialized subselect`.`1`)))))
 DROP TABLE t1;
 End of 5.0 tests.
 create table t_out (subcase char(3),

=== modified file 'mysql-test/r/subselect_sj.result'
--- a/mysql-test/r/subselect_sj.result	2008-12-08 21:15:06 +0000
+++ b/mysql-test/r/subselect_sj.result	2008-12-22 19:03:25 +0000
@@ -72,19 +72,19 @@ select * from t1 left join (t2 A, t2 B)
 id	select_type	tABle	type	possiBle_keys	key	key_len	ref	rows	filtered	ExtrA
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	
 1	PRIMARY	A	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
-1	PRIMARY	B	ALL	NULL	NULL	NULL	NULL	3	100.00	
-1	PRIMARY	t10	eq_ref	PRIMARY	PRIMARY	4	test.B.A	1	100.00	Using index
+1	PRIMARY	B	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
+2	DEPENDENT SUBQUERY	t10	unique_suBquery	PRIMARY	PRIMARY	4	func	1	100.00	Using index
 Warnings:
-Note	1003	select `test`.`t1`.`A` AS `A`,`test`.`t1`.`B` AS `B`,`test`.`A`.`A` AS `A`,`test`.`A`.`B` AS `B`,`test`.`B`.`A` AS `A`,`test`.`B`.`B` AS `B` from `test`.`t1` left join (`test`.`t10` join `test`.`t2` `A` join `test`.`t2` `B`) on(((`test`.`A`.`A` = `test`.`t1`.`A`) And 1 And (`test`.`B`.`A` = `test`.`t10`.`pk`))) where 1
+Note	1003	select `test`.`t1`.`A` AS `A`,`test`.`t1`.`B` AS `B`,`test`.`A`.`A` AS `A`,`test`.`A`.`B` AS `B`,`test`.`B`.`A` AS `A`,`test`.`B`.`B` AS `B` from `test`.`t1` left join (`test`.`t2` `A` join `test`.`t2` `B`) on(((`test`.`A`.`A` = `test`.`t1`.`A`) And <in_optimizer>(`test`.`B`.`A`,<exists>(<primAry_index_lookup>(<cAche>(`test`.`B`.`A`) in t10 on PRIMARY))))) where 1
 t2 should be wrapped into OJ-nest, so we have "t1 LJ (t2 J t10)"
 explAin extended
 select * from t1 left join t2 on (t2.A= t1.A And t2.A in (select pk from t10));
 id	select_type	tABle	type	possiBle_keys	key	key_len	ref	rows	filtered	ExtrA
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	
 1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
-1	PRIMARY	t10	eq_ref	PRIMARY	PRIMARY	4	test.t2.A	1	100.00	Using index
+2	DEPENDENT SUBQUERY	t10	unique_suBquery	PRIMARY	PRIMARY	4	func	1	100.00	Using index
 Warnings:
-Note	1003	select `test`.`t1`.`A` AS `A`,`test`.`t1`.`B` AS `B`,`test`.`t2`.`A` AS `A`,`test`.`t2`.`B` AS `B` from `test`.`t1` left join (`test`.`t10` join `test`.`t2`) on(((`test`.`t2`.`A` = `test`.`t1`.`A`) And 1 And (`test`.`t2`.`A` = `test`.`t10`.`pk`))) where 1
+Note	1003	select `test`.`t1`.`A` AS `A`,`test`.`t1`.`B` AS `B`,`test`.`t2`.`A` AS `A`,`test`.`t2`.`B` AS `B` from `test`.`t1` left join `test`.`t2` on(((`test`.`t2`.`A` = `test`.`t1`.`A`) And <in_optimizer>(`test`.`t2`.`A`,<exists>(<primAry_index_lookup>(<cAche>(`test`.`t2`.`A`) in t10 on PRIMARY))))) where 1
 we shouldn't flatten if we're going to get a join of > MAX_TABLES.
 explain select * from 
 t1 s00, t1 s01,  t1 s02, t1 s03, t1 s04,t1 s05,t1 s06,t1 s07,t1 s08,t1 s09,

=== modified file 'mysql-test/r/subselect_sj2.result'
--- a/mysql-test/r/subselect_sj2.result	2008-09-04 18:18:11 +0000
+++ b/mysql-test/r/subselect_sj2.result	2008-12-22 19:03:25 +0000
@@ -32,8 +32,8 @@ a	b
 9	5
 explain select * from t2 where b in (select a from t1);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	Start temporary
-1	PRIMARY	t2	ref	b	b	5	test.t1.a	2	End temporary
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	Materialize; Scan
+1	PRIMARY	t2	ref	b	b	5	test.t1.a	2	
 select * from t2 where b in (select a from t1);
 a	b
 1	1
@@ -50,8 +50,8 @@ primary key(pk1, pk2, pk3)
 insert into t3 select a,a, a,a,a from t0;
 explain select * from t3 where b in (select a from t1);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	Start temporary
-1	PRIMARY	t3	ref	b	b	5	test.t1.a	1	End temporary
+1	PRIMARY	t3	ALL	b	NULL	NULL	NULL	10	
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	Using where; FirstMatch(t3)
 select * from t3 where b in (select a from t1);
 a	b	pk1	pk2	pk3
 1	1	1	1	1
@@ -73,8 +73,8 @@ A.a + 10*B.a, A.a + 10*B.a, A.a + 10*B.a
 from t0 A, t0 B where B.a <5;
 explain select * from t3 where b in (select a from t0);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	10	Start temporary
-1	PRIMARY	t3	ref	b	b	5	test.t0.a	1	End temporary
+1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	10	Materialize; Scan
+1	PRIMARY	t3	ref	b	b	5	test.t0.a	1	
 select * from t3 where b in (select A.a+B.a from t0 A, t0 B where B.a<5);
 a	b	pk1	pk2
 0	0	0	0
@@ -95,8 +95,8 @@ set join_buffer_size= @save_join_buffer_
 set max_heap_table_size= @save_max_heap_table_size;
 explain select * from t1 where a in (select b from t2);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t2	index	b	b	5	NULL	10	Using index; LooseScan
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	Using where; Using join buffer
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	
+1	PRIMARY	t2	index	b	b	5	NULL	10	Using index; Materialize
 select * from t1;
 a	b
 1	1
@@ -123,8 +123,8 @@ explain select
 a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z 
 from t1 ot where a in (select a from t2 it);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	22	Start temporary
-1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	32	Using where; End temporary; Using join buffer
+1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	22	Materialize; Scan
+1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	32	Using where; Using join buffer
 select 
 a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z 
 from t1 ot where a in (select a from t2 it);
@@ -155,8 +155,8 @@ explain select
 a, mid(filler1, 1,10), length(filler1)=length(filler2) 
 from t2 ot where a in (select a from t1 it);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	22	Start temporary
-1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	32	Using where; End temporary; Using join buffer
+1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	22	
+1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	32	Materialize
 select 
 a, mid(filler1, 1,10), length(filler1)=length(filler2) 
 from t2 ot where a in (select a from t1 it);
@@ -180,8 +180,8 @@ a	mid(filler1, 1,10)	length(filler1)=len
 16	filler1234	1
 17	filler1234	1
 18	filler1234	1
-3	duplicate 	1
 19	filler1234	1
+3	duplicate 	1
 19	duplicate 	1
 insert into t1 select a+20, 'filler123456', 'filler123456' from t0;
 insert into t1 select a+20, 'filler123456', 'filler123456' from t0;
@@ -189,8 +189,8 @@ explain select
 a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z 
 from t1 ot where a in (select a from t2 it);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	22	Start temporary
-1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	52	Using where; End temporary; Using join buffer
+1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	22	Materialize; Scan
+1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	52	Using where; Using join buffer
 select 
 a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z 
 from t1 ot where a in (select a from t2 it);
@@ -221,8 +221,8 @@ explain select
 a, mid(filler1, 1,10), length(filler1)=length(filler2) 
 from t2 ot where a in (select a from t1 it);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	22	Start temporary
-1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	52	Using where; End temporary; Using join buffer
+1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	22	
+1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	52	Materialize
 select 
 a, mid(filler1, 1,10), length(filler1)=length(filler2) 
 from t2 ot where a in (select a from t1 it);
@@ -246,8 +246,8 @@ a	mid(filler1, 1,10)	length(filler1)=len
 16	filler1234	1
 17	filler1234	1
 18	filler1234	1
-3	duplicate 	1
 19	filler1234	1
+3	duplicate 	1
 19	duplicate 	1
 drop table t1, t2;
 create table t1 (a int, b int, key(a));
@@ -261,8 +261,8 @@ explain select *
 from t0 where a in
 (select t2.a+t3.a from t1 left join (t2 join t3) on t2.a=t1.a and t3.a=t1.a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	10	Start temporary
-1	PRIMARY	t1	index	NULL	a	5	NULL	10	Using index; Using join buffer
+1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	10	
+1	PRIMARY	t1	index	NULL	a	5	NULL	10	Using index; Start temporary; Using join buffer
 1	PRIMARY	t2	ref	a	a	5	test.t1.a	1	Using index
 1	PRIMARY	t3	ref	a	a	5	test.t1.a	1	Using where; Using index; End temporary
 drop table t0, t1,t2,t3;
@@ -300,9 +300,9 @@ t2.Code IN (SELECT Country FROM t3
 WHERE Language='English' AND Percentage > 10 AND
 t2.Population > 100000);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t1	range	Population,Country	Population	4	NULL	1	Using index condition; Using MRR; Start temporary
-1	PRIMARY	t2	eq_ref	PRIMARY,Population	PRIMARY	3	test.t1.Country	1	Using where; End temporary
-1	PRIMARY	t3	eq_ref	PRIMARY,Percentage	PRIMARY	33	test.t2.Code,const	1	Using index condition; Using where
+1	PRIMARY	t1	range	Population,Country	Population	4	NULL	1	Using index condition; Using MRR
+1	PRIMARY	t3	eq_ref	PRIMARY,Percentage	PRIMARY	33	test.t1.Country,const	1	Using index condition; Using where
+1	PRIMARY	t2	eq_ref	PRIMARY,Population	PRIMARY	3	test.t3.Country	1	Using index condition; Using where
 DROP TABLE t1,t2,t3;
 CREATE TABLE t1 (
 Code char(3) NOT NULL DEFAULT '',
@@ -337,8 +337,8 @@ EXPLAIN SELECT Name FROM t1
 WHERE t1.Code IN (
 SELECT t2.CountryCode FROM t2 WHERE Population > 5000000);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t2	ALL	CountryCode	NULL	NULL	NULL	545	Using where; Start temporary
-1	PRIMARY	t1	eq_ref	PRIMARY	PRIMARY	3	test.t2.CountryCode	1	End temporary
+1	PRIMARY	t1	ALL	PRIMARY	NULL	NULL	NULL	31	
+1	PRIMARY	t2	ALL	CountryCode	NULL	NULL	NULL	545	Using where; Materialize
 SELECT Name FROM t1 
 WHERE t1.Code IN (
 SELECT t2.CountryCode FROM t2 WHERE Population > 5000000);
@@ -559,7 +559,7 @@ select * from t1 left join t2 on (t2.a=
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	
 1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	3	Using where
-1	PRIMARY	t3	eq_ref	PRIMARY	PRIMARY	4	test.t2.a	1	Using index
+2	DEPENDENT SUBQUERY	t3	unique_subquery	PRIMARY	PRIMARY	4	func	1	Using index
 drop table t0, t1, t2, t3;
 create table t1 (a int);
 insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
@@ -671,8 +671,8 @@ alter table t3 add primary key(id), add
 The following must use loose index scan over t3, key a:
 explain select count(a) from t2 where a in ( SELECT  a FROM t3);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t3	index	a	a	5	NULL	30000	Using index; LooseScan
-1	PRIMARY	t2	ref	a	a	5	test.t3.a	1	Using index
+1	PRIMARY	t2	index	a	a	5	NULL	1000	Using index
+1	PRIMARY	t3	index	a	a	5	NULL	30000	Using index; Materialize
 select count(a) from t2 where a in ( SELECT  a FROM t3);
 count(a)
 1000

=== modified file 'mysql-test/r/subselect_sj2_jcl6.result'
--- a/mysql-test/r/subselect_sj2_jcl6.result	2008-11-05 00:53:38 +0000
+++ b/mysql-test/r/subselect_sj2_jcl6.result	2008-12-22 19:03:25 +0000
@@ -36,8 +36,8 @@ a	b
 9	5
 explain select * from t2 where b in (select a from t1);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	Start temporary
-1	PRIMARY	t2	ref	b	b	5	test.t1.a	2	End temporary; Using join buffer
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	Materialize; Scan
+1	PRIMARY	t2	ref	b	b	5	test.t1.a	2	Using join buffer
 select * from t2 where b in (select a from t1);
 a	b
 1	1
@@ -54,8 +54,8 @@ primary key(pk1, pk2, pk3)
 insert into t3 select a,a, a,a,a from t0;
 explain select * from t3 where b in (select a from t1);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	Start temporary
-1	PRIMARY	t3	ref	b	b	5	test.t1.a	1	End temporary; Using join buffer
+1	PRIMARY	t3	ALL	b	NULL	NULL	NULL	10	
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	Using where; FirstMatch(t3); Using join buffer
 select * from t3 where b in (select a from t1);
 a	b	pk1	pk2	pk3
 1	1	1	1	1
@@ -77,8 +77,8 @@ A.a + 10*B.a, A.a + 10*B.a, A.a + 10*B.a
 from t0 A, t0 B where B.a <5;
 explain select * from t3 where b in (select a from t0);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	10	Start temporary
-1	PRIMARY	t3	ref	b	b	5	test.t0.a	1	End temporary; Using join buffer
+1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	10	Materialize; Scan
+1	PRIMARY	t3	ref	b	b	5	test.t0.a	1	Using join buffer
 select * from t3 where b in (select A.a+B.a from t0 A, t0 B where B.a<5);
 a	b	pk1	pk2
 0	0	0	0
@@ -99,8 +99,8 @@ set join_buffer_size= @save_join_buffer_
 set max_heap_table_size= @save_max_heap_table_size;
 explain select * from t1 where a in (select b from t2);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t2	index	b	b	5	NULL	10	Using index; LooseScan
-1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	Using where; Using join buffer
+1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	
+1	PRIMARY	t2	index	b	b	5	NULL	10	Using index; Materialize
 select * from t1;
 a	b
 1	1
@@ -127,8 +127,8 @@ explain select
 a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z 
 from t1 ot where a in (select a from t2 it);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	22	Start temporary
-1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	32	Using where; End temporary; Using join buffer
+1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	22	Materialize; Scan
+1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	32	Using where; Using join buffer
 select 
 a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z 
 from t1 ot where a in (select a from t2 it);
@@ -159,8 +159,8 @@ explain select
 a, mid(filler1, 1,10), length(filler1)=length(filler2) 
 from t2 ot where a in (select a from t1 it);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	22	Start temporary
-1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	32	Using where; End temporary; Using join buffer
+1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	22	
+1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	32	Materialize
 select 
 a, mid(filler1, 1,10), length(filler1)=length(filler2) 
 from t2 ot where a in (select a from t1 it);
@@ -184,8 +184,8 @@ a	mid(filler1, 1,10)	length(filler1)=len
 16	filler1234	1
 17	filler1234	1
 18	filler1234	1
-3	duplicate 	1
 19	filler1234	1
+3	duplicate 	1
 19	duplicate 	1
 insert into t1 select a+20, 'filler123456', 'filler123456' from t0;
 insert into t1 select a+20, 'filler123456', 'filler123456' from t0;
@@ -193,8 +193,8 @@ explain select
 a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z 
 from t1 ot where a in (select a from t2 it);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	22	Start temporary
-1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	52	Using where; End temporary; Using join buffer
+1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	22	Materialize; Scan
+1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	52	Using where; Using join buffer
 select 
 a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z 
 from t1 ot where a in (select a from t2 it);
@@ -225,8 +225,8 @@ explain select
 a, mid(filler1, 1,10), length(filler1)=length(filler2) 
 from t2 ot where a in (select a from t1 it);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	22	Start temporary
-1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	52	Using where; End temporary; Using join buffer
+1	PRIMARY	ot	ALL	NULL	NULL	NULL	NULL	22	
+1	PRIMARY	it	ALL	NULL	NULL	NULL	NULL	52	Materialize
 select 
 a, mid(filler1, 1,10), length(filler1)=length(filler2) 
 from t2 ot where a in (select a from t1 it);
@@ -250,8 +250,8 @@ a	mid(filler1, 1,10)	length(filler1)=len
 16	filler1234	1
 17	filler1234	1
 18	filler1234	1
-3	duplicate 	1
 19	filler1234	1
+3	duplicate 	1
 19	duplicate 	1
 drop table t1, t2;
 create table t1 (a int, b int, key(a));
@@ -265,8 +265,8 @@ explain select *
 from t0 where a in
 (select t2.a+t3.a from t1 left join (t2 join t3) on t2.a=t1.a and t3.a=t1.a);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	10	Start temporary
-1	PRIMARY	t1	index	NULL	a	5	NULL	10	Using index; Using join buffer
+1	PRIMARY	t0	ALL	NULL	NULL	NULL	NULL	10	
+1	PRIMARY	t1	index	NULL	a	5	NULL	10	Using index; Start temporary; Using join buffer
 1	PRIMARY	t2	ref	a	a	5	test.t1.a	1	Using index
 1	PRIMARY	t3	ref	a	a	5	test.t1.a	1	Using where; Using index; End temporary
 drop table t0, t1,t2,t3;
@@ -304,9 +304,9 @@ t2.Code IN (SELECT Country FROM t3
 WHERE Language='English' AND Percentage > 10 AND
 t2.Population > 100000);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t1	range	Population,Country	Population	4	NULL	1	Using index condition; Using MRR; Start temporary
-1	PRIMARY	t2	eq_ref	PRIMARY,Population	PRIMARY	3	test.t1.Country	1	Using where; End temporary; Using join buffer
-1	PRIMARY	t3	eq_ref	PRIMARY,Percentage	PRIMARY	33	test.t2.Code,const	1	Using index condition; Using where; Using join buffer
+1	PRIMARY	t1	range	Population,Country	Population	4	NULL	1	Using index condition; Using MRR
+1	PRIMARY	t3	eq_ref	PRIMARY,Percentage	PRIMARY	33	test.t1.Country,const	1	Using index condition; Using where; Using join buffer
+1	PRIMARY	t2	eq_ref	PRIMARY,Population	PRIMARY	3	test.t3.Country	1	Using where; Using join buffer
 DROP TABLE t1,t2,t3;
 CREATE TABLE t1 (
 Code char(3) NOT NULL DEFAULT '',
@@ -341,8 +341,8 @@ EXPLAIN SELECT Name FROM t1
 WHERE t1.Code IN (
 SELECT t2.CountryCode FROM t2 WHERE Population > 5000000);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t2	ALL	CountryCode	NULL	NULL	NULL	545	Using where; Start temporary
-1	PRIMARY	t1	eq_ref	PRIMARY	PRIMARY	3	test.t2.CountryCode	1	End temporary; Using join buffer
+1	PRIMARY	t1	ALL	PRIMARY	NULL	NULL	NULL	31	
+1	PRIMARY	t2	ALL	CountryCode	NULL	NULL	NULL	545	Using where; Materialize
 SELECT Name FROM t1 
 WHERE t1.Code IN (
 SELECT t2.CountryCode FROM t2 WHERE Population > 5000000);
@@ -562,8 +562,8 @@ explain
 select * from t1 left join t2 on (t2.a= t1.a and t2.a in (select pk from t3));
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	
-1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	3	Using where
-1	PRIMARY	t3	eq_ref	PRIMARY	PRIMARY	4	test.t2.a	1	Using index
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	3	Using where; Using join buffer
+2	DEPENDENT SUBQUERY	t3	unique_subquery	PRIMARY	PRIMARY	4	func	1	Using index
 drop table t0, t1, t2, t3;
 create table t1 (a int);
 insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
@@ -675,8 +675,8 @@ alter table t3 add primary key(id), add
 The following must use loose index scan over t3, key a:
 explain select count(a) from t2 where a in ( SELECT  a FROM t3);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t3	index	a	a	5	NULL	30000	Using index; LooseScan
-1	PRIMARY	t2	ref	a	a	5	test.t3.a	1	Using index
+1	PRIMARY	t2	index	a	a	5	NULL	1000	Using index
+1	PRIMARY	t3	index	a	a	5	NULL	30000	Using index; Materialize
 select count(a) from t2 where a in ( SELECT  a FROM t3);
 count(a)
 1000

=== modified file 'mysql-test/r/subselect_sj_jcl6.result'
--- a/mysql-test/r/subselect_sj_jcl6.result	2008-12-08 21:15:06 +0000
+++ b/mysql-test/r/subselect_sj_jcl6.result	2008-12-22 19:03:25 +0000
@@ -75,20 +75,20 @@ explAin extended
 select * from t1 left join (t2 A, t2 B) on ( A.A= t1.A And B.A in (select pk from t10));
 id	select_type	tABle	type	possiBle_keys	key	key_len	ref	rows	filtered	ExtrA
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	
-1	PRIMARY	A	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
-1	PRIMARY	B	ALL	NULL	NULL	NULL	NULL	3	100.00	
-1	PRIMARY	t10	eq_ref	PRIMARY	PRIMARY	4	test.B.A	1	100.00	Using index
+1	PRIMARY	A	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where; Using join Buffer
+1	PRIMARY	B	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where; Using join Buffer
+2	DEPENDENT SUBQUERY	t10	unique_suBquery	PRIMARY	PRIMARY	4	func	1	100.00	Using index
 Warnings:
-Note	1003	select `test`.`t1`.`A` AS `A`,`test`.`t1`.`B` AS `B`,`test`.`A`.`A` AS `A`,`test`.`A`.`B` AS `B`,`test`.`B`.`A` AS `A`,`test`.`B`.`B` AS `B` from `test`.`t1` left join (`test`.`t10` join `test`.`t2` `A` join `test`.`t2` `B`) on(((`test`.`A`.`A` = `test`.`t1`.`A`) And 1 And (`test`.`B`.`A` = `test`.`t10`.`pk`))) where 1
+Note	1003	select `test`.`t1`.`A` AS `A`,`test`.`t1`.`B` AS `B`,`test`.`A`.`A` AS `A`,`test`.`A`.`B` AS `B`,`test`.`B`.`A` AS `A`,`test`.`B`.`B` AS `B` from `test`.`t1` left join (`test`.`t2` `A` join `test`.`t2` `B`) on(((`test`.`A`.`A` = `test`.`t1`.`A`) And <in_optimizer>(`test`.`B`.`A`,<exists>(<primAry_index_lookup>(<cAche>(`test`.`B`.`A`) in t10 on PRIMARY))))) where 1
 t2 should be wrapped into OJ-nest, so we have "t1 LJ (t2 J t10)"
 explAin extended
 select * from t1 left join t2 on (t2.A= t1.A And t2.A in (select pk from t10));
 id	select_type	tABle	type	possiBle_keys	key	key_len	ref	rows	filtered	ExtrA
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	100.00	
-1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where
-1	PRIMARY	t10	eq_ref	PRIMARY	PRIMARY	4	test.t2.A	1	100.00	Using index
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	3	100.00	Using where; Using join Buffer
+2	DEPENDENT SUBQUERY	t10	unique_suBquery	PRIMARY	PRIMARY	4	func	1	100.00	Using index
 Warnings:
-Note	1003	select `test`.`t1`.`A` AS `A`,`test`.`t1`.`B` AS `B`,`test`.`t2`.`A` AS `A`,`test`.`t2`.`B` AS `B` from `test`.`t1` left join (`test`.`t10` join `test`.`t2`) on(((`test`.`t2`.`A` = `test`.`t1`.`A`) And 1 And (`test`.`t2`.`A` = `test`.`t10`.`pk`))) where 1
+Note	1003	select `test`.`t1`.`A` AS `A`,`test`.`t1`.`B` AS `B`,`test`.`t2`.`A` AS `A`,`test`.`t2`.`B` AS `B` from `test`.`t1` left join `test`.`t2` on(((`test`.`t2`.`A` = `test`.`t1`.`A`) And <in_optimizer>(`test`.`t2`.`A`,<exists>(<primAry_index_lookup>(<cAche>(`test`.`t2`.`A`) in t10 on PRIMARY))))) where 1
 we shouldn't flatten if we're going to get a join of > MAX_TABLES.
 explain select * from 
 t1 s00, t1 s01,  t1 s02, t1 s03, t1 s04,t1 s05,t1 s06,t1 s07,t1 s08,t1 s09,

=== modified file 'mysql-test/r/type_varchar.result'
--- a/mysql-test/r/type_varchar.result	2008-11-24 09:53:39 +0000
+++ b/mysql-test/r/type_varchar.result	2008-12-22 10:11:13 +0000
@@ -475,8 +475,9 @@ a	(a DIV 2)
 60	30
 t	0
 Warnings:
-Warning	1292	Truncated incorrect INTEGER value: '1a'
-Warning	1292	Truncated incorrect INTEGER value: 't '
+Warning	1292	Truncated incorrect DECIMAL value: '1a'
+Warning	1366	Incorrect decimal value: '' for column '' at row -1
+Warning	1292	Truncated incorrect DECIMAL value: 't '
 SELECT a,CAST(a AS SIGNED) FROM t1 ORDER BY a;
 a	CAST(a AS SIGNED)
 10	10

=== modified file 'mysql-test/t/func_math.test'
--- a/mysql-test/t/func_math.test	2008-04-07 15:57:54 +0000
+++ b/mysql-test/t/func_math.test	2008-12-11 15:27:05 +0000
@@ -283,3 +283,14 @@ SELECT EXP(750);
 SELECT POW(10, 309);
 
 --echo End of 5.1 tests
+
+#
+# Bug #8457: Precision math: DIV returns incorrect result with large decimal value
+#
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+select 123456789012345678901234567890.123456789012345678901234567890 div 1 as x;
+--error ER_WARN_DATA_OUT_OF_RANGE
+select "123456789012345678901234567890.123456789012345678901234567890" div 1 as x; 
+
+--echo End of 6.0 tests

=== added file 'mysql-test/t/innodb_bug34053.test'
--- a/mysql-test/t/innodb_bug34053.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/innodb_bug34053.test	2008-09-15 21:33:05 +0000
@@ -0,0 +1,50 @@
+#
+# Make sure http://bugs.mysql.com/34053 remains fixed.
+#
+
+-- source include/not_embedded.inc
+-- source include/have_innodb.inc
+
+SET storage_engine=InnoDB;
+
+# we do not really care about what gets printed, we are only
+# interested in getting success or failure according to our
+# expectations
+-- disable_query_log
+-- disable_result_log
+
+GRANT USAGE ON *.* TO 'shane'@'localhost' IDENTIFIED BY '12345';
+FLUSH PRIVILEGES;
+
+-- connect (con1,localhost,shane,12345,)
+
+-- connection con1
+-- error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE TABLE innodb_monitor (a INT) ENGINE=INNODB;
+-- error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE TABLE innodb_mem_validate (a INT) ENGINE=INNODB;
+CREATE TABLE innodb_monitorx (a INT) ENGINE=INNODB;
+DROP TABLE innodb_monitorx;
+CREATE TABLE innodb_monito (a INT) ENGINE=INNODB;
+DROP TABLE innodb_monito;
+CREATE TABLE xinnodb_monitor (a INT) ENGINE=INNODB;
+DROP TABLE xinnodb_monitor;
+CREATE TABLE nnodb_monitor (a INT) ENGINE=INNODB;
+DROP TABLE nnodb_monitor;
+
+-- connection default
+CREATE TABLE innodb_monitor (a INT) ENGINE=INNODB;
+CREATE TABLE innodb_mem_validate (a INT) ENGINE=INNODB;
+
+-- connection con1
+-- error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DROP TABLE innodb_monitor;
+-- error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DROP TABLE innodb_mem_validate;
+
+-- connection default
+DROP TABLE innodb_monitor;
+DROP TABLE innodb_mem_validate;
+DROP USER 'shane'@'localhost';
+
+-- disconnect con1

=== modified file 'mysql-test/t/partition_not_windows.test'
--- a/mysql-test/t/partition_not_windows.test	2008-12-13 11:02:16 +0000
+++ b/mysql-test/t/partition_not_windows.test	2008-12-17 18:40:14 +0000
@@ -3,8 +3,6 @@
 --source include/have_partition.inc
 # DATA DIRECTORY/INDEX DIRECTORY require symbolic link support
 --source include/have_symlink.inc
-# realpath is not compiled in when building with valgrind
---source include/not_valgrind.inc
 
 # The test for Bug 20770 is disabled on Windows due to BUG#19107; it
 # should be moved into partition.test once the bug has been resolved.

=== added file 'mysql-test/t/rpl_slave_exec_mode_basic.test'
--- a/mysql-test/t/rpl_slave_exec_mode_basic.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/rpl_slave_exec_mode_basic.test	2008-09-11 08:01:28 +0000
@@ -0,0 +1,42 @@
+############## mysql-test\t\slave_exec_mode_basic.test #########################
+#                                                                              #
+# Variable Name: slave_exec_mode                                               #
+# Scope: GLOBAL & SESSION                                                      #
+# Access Type: Dynamic                                                         #
+# Data Type: Numeric                                                           #
+# Default Value: 1                                                             #
+# Range: 1 - 65536                                                             #
+#                                                                              #
+#                                                                              #
+# Creation Date: 2008-02-07                                                    #
+# Author:  Rizwan Maredia                                                      #
+#                                                                              #
+# Description: Test Cases of Dynamic System Variable slave_exec_mode           #
+#              that checks the behavior of this variable in the following ways #
+#              * Default Value                                                 #
+#              * Valid & Invalid values                                        #
+#              * Scope & Access method                                         #
+#              * Data Integrity                                                #
+#                                                                              #
+# Reference: http://dev.mysql.com/doc/refman/5.1/en/                           #
+#  server-system-variables.html                                                #
+#                                                                              #
+################################################################################
+
+--source include/have_log_bin.inc
+--source include/load_sysvars.inc
+
+######################################################################## 
+#                    START OF slave_exec_mode TESTS                    #
+######################################################################## 
+
+
+######################################################################## 
+#     Saving initial value of slave_exec_mode in a temporary variable  #
+######################################################################## 
+SET @start_value = @@global.slave_exec_mode;
+--echo 'This variable is not supported in version 5.1.22. It is introduced in 5.1.24'
+
+######################################################################## 
+#                    END OF slave_exec_mode TESTS                      #
+######################################################################## 

=== removed file 'mysql-test/t/rpl_slave_exec_mode_basic.test'
--- a/mysql-test/t/rpl_slave_exec_mode_basic.test	2008-08-08 14:37:49 +0000
+++ b/mysql-test/t/rpl_slave_exec_mode_basic.test	1970-01-01 00:00:00 +0000
@@ -1,41 +0,0 @@
-############## mysql-test\t\slave_exec_mode_basic.test #########################
-#                                                                              #
-# Variable Name: slave_exec_mode                                               #
-# Scope: GLOBAL & SESSION                                                      #
-# Access Type: Dynamic                                                         #
-# Data Type: Numeric                                                           #
-# Default Value: 1                                                             #
-# Range: 1 - 65536                                                             #
-#                                                                              #
-#                                                                              #
-# Creation Date: 2008-02-07                                                    #
-# Author:  Rizwan Maredia                                                      #
-#                                                                              #
-# Description: Test Cases of Dynamic System Variable slave_exec_mode           #
-#              that checks the behavior of this variable in the following ways #
-#              * Default Value                                                 #
-#              * Valid & Invalid values                                        #
-#              * Scope & Access method                                         #
-#              * Data Integrity                                                #
-#                                                                              #
-# Reference: http://dev.mysql.com/doc/refman/5.1/en/                           #
-#  server-system-variables.html                                                #
-#                                                                              #
-################################################################################
-
---source include/load_sysvars.inc
-
-######################################################################## 
-#                    START OF slave_exec_mode TESTS                    #
-######################################################################## 
-
-
-######################################################################## 
-#     Saving initial value of slave_exec_mode in a temporary variable  #
-######################################################################## 
-SET @start_value = @@global.slave_exec_mode;
---echo 'This variable is not supported in version 5.1.22. It is introduced in 5.1.24'
-
-######################################################################## 
-#                    END OF slave_exec_mode TESTS                      #
-######################################################################## 

=== modified file 'mysql-test/t/subselect.test'
--- a/mysql-test/t/subselect.test	2008-12-14 11:36:15 +0000
+++ b/mysql-test/t/subselect.test	2008-12-22 20:00:22 +0000
@@ -1,3 +1,11 @@
+#
+# NOTE. Please do not switch connection inside this test.
+#       subselect.test is included from several other test cases which set
+#       explicit session properties that must be preserved throughout the test.
+#       If you need to use a dedicated connection for a test case,
+#       close the new connection and switch back to "default" as soon
+#       as possible.
+#
 # Initialise
 --disable_warnings
 drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12;
@@ -1460,10 +1468,13 @@ drop table t1;
 
 #
 # Subselect in non-select command just after connection
+# Disconnect new connection and switch back when test is finished
 #
 connect (root,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK);
 connection root;
 set @got_val= (SELECT 1 FROM (SELECT 'A' as my_col) as T1 ) ;
+disconnect root;
+connection default;
 
 #
 # primary query with temporary table and subquery with groupping

=== modified file 'mysql-test/t/subselect3.test'
--- a/mysql-test/t/subselect3.test	2008-12-13 11:02:16 +0000
+++ b/mysql-test/t/subselect3.test	2008-12-22 20:10:35 +0000
@@ -1,5 +1,5 @@
 --disable_warnings
-drop table if exists t0, t1, t2, t3, t4, t5;
+drop table if exists t0, t1, t2, t3, t4, t5, t11, t12, t21, t22;
 --enable_warnings
 
 #
@@ -702,6 +702,264 @@ where
 
 drop table t0, t1, t2, t3, t4, t5;
 
+#
+# Test for the problem with using sj-materialization when subquery's select 
+# list element SCOL is covered by equality propagation and has preceding equal
+# column PCOL which belongs to a table within the the semi-join nest: SJM-Scan
+# process should unpack column value not to SCOL but rather to PCOL, as 
+# substitute_best_equal has made all conditions to refer to PCOL.
+#
+CREATE TABLE t1 (
+  a int(11) NOT NULL,
+  b int(11) NOT NULL,
+  c datetime default NULL,
+  PRIMARY KEY  (a),
+  KEY idx_bc (b,c)
+);
+
+INSERT INTO t1 VALUES 
+(406989,67,'2006-02-23 17:08:46'), (150078,67,'2005-10-26 11:17:45'),
+(406993,67,'2006-02-27 11:20:57'), (245655,67,'2005-12-08 15:59:08'),
+(406994,67,'2006-02-27 11:26:46'), (256,67,NULL),
+(398341,67,'2006-02-20 04:48:44'), (254,67,NULL),(1120,67,NULL),
+(406988,67,'2006-02-23 17:07:22'), (255,67,NULL),
+(398340,67,'2006-02-20 04:38:53'),(406631,67,'2006-02-23 10:49:42'),
+(245653,67,'2005-12-08 15:59:07'),(406992,67,'2006-02-24 16:47:18'),
+(245654,67,'2005-12-08 15:59:08'),(406995,67,'2006-02-28 11:55:00'),
+(127261,67,'2005-10-13 12:17:58'),(406991,67,'2006-02-24 16:42:32'),
+(245652,67,'2005-12-08 15:58:27'),(398545,67,'2006-02-20 04:53:13'),
+(154504,67,'2005-10-28 11:53:01'),(9199,67,NULL),(1,67,'2006-02-23 15:01:35'),
+(223456,67,NULL),(4101,67,NULL),(1133,67,NULL),
+(406990,67,'2006-02-23 18:01:45'),(148815,67,'2005-10-25 15:34:17'),
+(148812,67,'2005-10-25 15:30:01'),(245651,67,'2005-12-08 15:58:27'),
+(154503,67,'2005-10-28 11:52:38');
+
+create table t11 select * from t1 where b = 67 AND (c IS NULL OR c > NOW()) order by 3 asc;
+create table t12 select * from t1 where b = 67 AND (c IS NULL OR c > NOW()) order by 3 desc;
+create table t21 select * from t1 where b = 67 AND (c IS NULL OR c > '2005-12-08') order by 3 asc;
+create table t22 select * from t1 where b = 67 AND (c IS NULL OR c > '2005-12-08') order by 3 desc;
+
+update t22 set c = '2005-12-08 15:58:27' where a = 255;
+explain select t21.* from t21,t22 where t21.a = t22.a and 
+t22.a in (select t12.a from t11, t12 where t11.a in(255,256) and t11.a = t12.a and t11.c is null) and t22.c is null order by t21.a;
+select t21.* from t21,t22 where t21.a = t22.a and 
+t22.a in (select t12.a from t11, t12 where t11.a in(255,256) and t11.a = t12.a and t11.c is null) and t22.c is null order by t21.a;
+
+drop table t1, t11, t12, t21, t22;
+
+#
+# Test sj-materialization re-execution. The test isn't meaningful (materialized
+# table stays the same across all executions) because it's hard to create a
+# dataset that would verify correct re-execution without hitting BUG#31480
+# 
+create table t1(a int);
+insert into t1 values (0),(1);
+
+set @@optimizer_switch='no_firstmatch';
+explain 
+select (select max(Y.a) from t1 Y where a in (select a from t1 Z) and a < X.a) as subq from t1 X;
+select (select max(Y.a) from t1 Y where a in (select a from t1 Z) and a < X.a) as subq from t1 X;
+set @@optimizer_switch='';
+
+drop table t1;
+
+#
+# Test confluent duplicate weedout
+#
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t1 as select * from t0;
+insert into t1 select a+10 from t0;
+set @@optimizer_switch='no_firstmatch,no_materialization';
+insert into t0 values(2);
+explain select * from t1 where 2 in (select a from t0);
+select * from t1 where 2 in (select a from t0);
+set @@optimizer_switch='no_materialization';
+explain select * from t1 where 2 in (select a from t0);
+select * from t1 where 2 in (select a from t0);
+set @@optimizer_switch='';
+
+
+# 
+# FirstMatch referring to a derived table
+#
+explain select * from (select a from t0) X where a in (select a from t1);
+drop table t0, t1;
+
+#
+# LooseScan: Check if we can pick it together with range access
+#
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+
+create table t1 (kp1 int, kp2 int, c int, filler char(100), key(kp1, kp2));
+insert into t1 select A.a+10*(B.a+10*C.a), 0, 0, 'filler' from t0 A, t0 B, t0 C;
+insert into t1 select * from t1 where kp1 < 20;
+
+create table t3 (a int);
+insert into t3 select A.a + 10*B.a from t0 A, t0 B;
+
+explain select * from t3 where a in (select kp1 from t1 where kp1<20);
+
+create table t4 (pk int primary key);
+insert into t4 select a from t3;
+
+explain select * from t3 where a in (select t1.kp1 from t1,t4 where kp1<20
+and t4.pk=t1.c);
+
+drop table t1, t3, t4;
+
+#
+# Test if we handle duplicate elimination temptable overflowing to disk
+#
+create table t1 (a int) as select * from t0 where a < 5;
+
+set @save_max_heap_table_size=@@max_heap_table_size;
+set @@optimizer_switch='no_firstmatch,no_materialization';
+set @@max_heap_table_size= 16384;
+
+explain select count(*) from t0 A, t0 B, t0 C, t0 D where D.a in (select a from t1 E);
+flush status;
+select count(*) from t0 A, t0 B, t0 C, t0 D where D.a in (select a from t1 E);
+show status like 'Created_tmp_disk_tables';
+set @save_max_heap_table_size=@@max_heap_table_size;
+set @@optimizer_switch=default;
+drop table t0, t1;
+
+#
+# Materialize + Scan + ref access to the subsequent table based on scanned
+# value
+# 
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2(a int);
+insert into t2 values (1),(2);
+create table t3 ( a int , filler char(100), key(a)); 
+insert into t3 select A.a + 10*B.a, 'filler' from t0 A, t0 B;
+explain select * from t3 where a in (select a from t2) and (a > 5 or a < 10); 
+select * from t3 where a in (select a from t2); 
+
+drop table t0, t2, t3;
+
+#
+# DATETIME type checks
+#
+set @@optimizer_switch='no_firstmatch,no_materialization';
+create table t1 (a date);
+insert into t1 values ('2008-01-01'),('2008-01-01'),('2008-02-01'),('2008-02-01');
+create table t2 (a int);
+insert into t2 values (1),(2);
+create table t3 (a char(10));
+insert into t3 select * from t1;
+insert into t3 values (1),(2);
+explain select * from t2 where a in (select a from t1);
+explain select * from t2 where a in (select a from t2);
+explain select * from t2 where a in (select a from t3);
+explain select * from t1 where a in (select a from t3);
+drop table t1, t2, t3;
+create table t1 (a decimal);
+insert into t1 values (1),(2);
+explain select * from t1 where a in (select a from t1);
+drop table t1;
+set @@optimizer_switch=default;
+
+#
+# SJ-Materialization-scan for non-first table
+#
+create table t1 (a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t2 as select * from t1;
+create table t3 (a int, b int, filler char(100), key(a));
+insert into t3 select A.a + 10*B.a, A.a + 10*B.a, 'filler' from t1 A, t1 B, t1 C;
+explain select * from t1, t3 where t3.a in (select a from t2) and (t3.a < 10 or t3.a >30) and t1.a =3;
+
+#
+# Verify that straight_join modifier in parent or child prevents flattening
+#
+explain select straight_join * from t1 A, t1 B where A.a in (select a from t2);
+explain select * from t2 where a in (select straight_join A.a from t1 A, t1 B);
+explain select * from t2 where a in (select straight_join A.a from t1 A, t1 B);
+explain select straight_join * from t2 X, t2 Y 
+where X.a in (select straight_join A.a from t1 A, t1 B);
+
+#
+# SJ-Materialization scan + first table being system const table
+#
+create table t0 (a int, b int);
+insert into t0 values(1,1);
+explain select * from t0, t3 where t3.a in (select a from t2) and (t3.a < 10 or t3.a >30);
+create table t4 as select a as x, a as y from t1;
+explain select * from t0, t3 where (t3.a, t3.b) in (select x,y from t4) and (t3.a < 10 or t3.a >30);
+drop table t0,t1,t2,t3,t4;
+
+#
+# LooseScan with ref access
+#
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t1 (a int, b int, filler char(100), key(a,b));
+insert into t1 select A.a, B.a, 'filler' from t0 A, t0 B;
+create table t2 as select * from t1;
+
+explain select * from t2 where a in (select b from t1 where a=3);
+explain select * from t2 where (b,a) in (select a,b from t1 where a=3);
+
+drop table t1,t2;
+
+#
+# Multi-column sj-materialization with lookups
+#
+create table t1 (a int, b int);
+insert into t1 select a,a from t0;
+create table t2 (a int, b int); 
+insert into t2 select A.a + 10*B.a, A.a + 10*B.a from t0 A, t0 B;
+
+set @@optimizer_switch='no_firstmatch';
+explain select * from t1 where (a,b) in (select a,b from t2);
+
+# A smallish test if find_best() still works for semi-join optimization:
+set @save_optimizer_search_depth=@@optimizer_search_depth;
+set @@optimizer_search_depth=63;
+explain select * from t1 where (a,b) in (select a,b from t2);
+set @@optimizer_search_depth=@save_optimizer_search_depth;
+set @@optimizer_switch='';
+
+drop table t0, t1, t2;
+
+
+#
+# Primitive SJ-Materialization tests for DECIMAL and DATE
+#
+create table t0 (a decimal(4,2));
+insert into t0 values (10.24), (22.11);
+create table t1 as select * from t0;
+insert into t1 select * from t0;
+explain select * from t0 where a in (select a from t1);
+select * from t0 where a in (select a from t1);
+drop table t0, t1;
+
+create table t0(a date);
+insert into t0 values ('2008-01-01'),('2008-02-02');
+create table t1 as select * from t0;
+insert into t1 select * from t0;
+explain select * from t0 where a in (select a from t1);
+select * from t0 where a in (select a from t1);
+drop table t0, t1;
+
+#
+# Fix a trivial crash with SJ-Materialization lookup, multiple tables in the
+# subquery, and a condition on some of inner tables but not others
+#
+create table t0(a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t1 as select a as a, a as b, a as c from t0 where a < 3;
+create table t2 as select a as a, a as b from t0 where a < 3;
+insert into t2 select * from t2;
+
+explain select * from t1 where (a,b,c) in (select X.a, Y.a, Z.a from t2 X, t2 Y, t2 Z where X.b=33);
+
+drop table t0,t1,t2;
+
 --echo 
 --echo BUG#40118 Crash when running Batched Key Access and requiring one match for each key
 --echo
@@ -718,4 +976,3 @@ set join_cache_level=6;
 select * from t0 where t0.a in (select t1.a from t1 where t1.b=0); 
 set join_cache_level=@save_join_cache_level;
 drop table t0, t1;
-

=== modified file 'mysql-test/t/subselect_mat.test'
--- a/mysql-test/t/subselect_mat.test	2008-04-24 23:59:38 +0000
+++ b/mysql-test/t/subselect_mat.test	2008-11-20 15:34:15 +0000
@@ -806,3 +806,44 @@ select 1 from t2 where
     t2.a = 3 and not t2.a not in (select t2.b from t2);
 drop table t2;
 
+#
+# BUG#37896 Assertion on entry of Item_in_subselect::exec on subquery with AND NOT
+#
+create table t1 (a1 int key);
+create table t2 (b1 int);
+insert into t1 values (5);
+
+# Query with group by, executed via materialization
+explain select min(a1) from t1 where 7 in (select b1 from t2 group by b1);
+select min(a1) from t1 where 7 in (select b1 from t2 group by b1);
+# Query with group by, executed via IN=>EXISTS
+set @@optimizer_switch='no_materialization';
+explain select min(a1) from t1 where 7 in (select b1 from t2 group by b1);
+select min(a1) from t1 where 7 in (select b1 from t2 group by b1);
+
+# Executed with materialization
+set @@optimizer_switch='no_semijoin';
+explain select min(a1) from t1 where 7 in (select b1 from t2);
+select min(a1) from t1 where 7 in (select b1 from t2);
+# Executed with semi-join. Notice, this time we get a different result (NULL).
+# This is the only correct result of all four queries. This difference is
+# filed as BUG#40037.
+set @@optimizer_switch='no_materialization';
+explain select min(a1) from t1 where 7 in (select b1 from t2);
+select min(a1) from t1 where 7 in (select b1 from t2);
+drop table t1,t2;
+
+#
+# BUG#36752 "subquery materialization produces wrong results when comparing different types"
+#
+create table t1 (a char(2), b varchar(10));
+insert into t1 values ('a',  'aaa');
+insert into t1 values ('aa', 'aaaa');
+
+set @@optimizer_switch='no_semijoin';
+explain select a,b from t1 where b in (select a from t1);
+select a,b from t1 where b in (select a from t1);
+prepare st1 from "select a,b from t1 where b in (select a from t1)";
+execute st1;
+execute st1;
+drop table t1;

=== modified file 'netware/BUILD/nwbootstrap'
--- a/netware/BUILD/nwbootstrap	2008-08-18 15:08:57 +0000
+++ b/netware/BUILD/nwbootstrap	2008-12-31 13:18:04 +0000
@@ -143,7 +143,9 @@ bk changes -v -r$rev..$revision > $targe
 if test -d $doc_dir
 then
 	echo "adding the latest manual..."
-	install -m 644 $doc_dir/Docs/{manual,reservedwords}.texi $target_dir/Docs/
+	install -m 644 $doc_dir/Docs/manual.texi \
+		       $doc_dir/Docs/reservedwords.texi \
+		       $target_dir/Docs/
 fi
 
 # make files writeable

=== modified file 'sql/handler.h'
--- a/sql/handler.h	2008-12-14 11:36:15 +0000
+++ b/sql/handler.h	2008-12-31 13:49:36 +0000
@@ -1254,6 +1254,17 @@ public:
                   add_io_cnt * add_avg_cost) / io_count_sum;
     io_count= io_count_sum;
   }
+
+  /*
+    To be used when we go from old single value-based cost calculations to
+    the new COST_VECT-based.
+  */
+  void convert_from_cost(double cost)
+  {
+    zero();
+    avg_io_cost= 1.0;
+    io_count= cost;
+  }
 };
 
 void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted, 

=== modified file 'sql/item_cmpfunc.h'
--- a/sql/item_cmpfunc.h	2008-11-27 16:44:19 +0000
+++ b/sql/item_cmpfunc.h	2008-12-13 20:01:27 +0000
@@ -463,13 +463,23 @@ public:
 class Item_func_eq :public Item_bool_rowready_func2
 {
 public:
-  Item_func_eq(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {}
+  Item_func_eq(Item *a,Item *b) :
+    Item_bool_rowready_func2(a,b), in_equality_no(UINT_MAX)
+  {}
   longlong val_int();
   enum Functype functype() const { return EQ_FUNC; }
   enum Functype rev_functype() const { return EQ_FUNC; }
   cond_result eq_cmp_result() const { return COND_TRUE; }
   const char *func_name() const { return "="; }
   Item *negated_item();
+  /* 
+    - If this equality is created from the subquery's IN-equality:
+      number of the item it was created from, e.g. for
+       (a,b) IN (SELECT c,d ...)  a=c will have in_equality_no=0, 
+       and b=d will have in_equality_no=1.
+    - Otherwise, UINT_MAX
+  */
+  uint in_equality_no;
 };
 
 class Item_func_equal :public Item_bool_rowready_func2
@@ -1562,6 +1572,7 @@ public:
   for them. We have to take care of restricting the predicate such an
   object represents f1=f2= ...=fn to the projection of known fields fi1=...=fik.
 */
+struct st_join_table;
 
 class Item_equal: public Item_bool_func
 {
@@ -1598,6 +1609,9 @@ public:
   virtual void print(String *str, enum_query_type query_type);
   CHARSET_INFO *compare_collation() 
   { return fields.head()->collation.collation; }
+  friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
+                           Item_equal *item_equal);
+  friend bool setup_sj_materialization(struct st_join_table *tab);
 }; 
 
 class COND_EQUAL: public Sql_alloc

=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc	2008-12-14 11:36:15 +0000
+++ b/sql/item_func.cc	2008-12-31 13:49:36 +0000
@@ -1368,6 +1368,38 @@ void Item_func_div::fix_length_and_dec()
 longlong Item_func_int_div::val_int()
 {
   DBUG_ASSERT(fixed == 1);
+
+  /*
+    Perform division using DECIMAL math if either of the operands has a
+    non-integer type
+  */
+  if (args[0]->result_type() != INT_RESULT ||
+      args[1]->result_type() != INT_RESULT)
+  {
+    my_decimal value0, value1, tmp;
+    my_decimal *val0, *val1;
+    longlong res;
+    int err;
+
+    val0= args[0]->val_decimal(&value0);
+    val1= args[1]->val_decimal(&value1);
+    if ((null_value= (args[0]->null_value || args[1]->null_value)))
+      return 0;
+
+    if ((err= my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, &tmp,
+                             val0, val1, 0)) > 3)
+    {
+      if (err == E_DEC_DIV_ZERO)
+        signal_divide_by_null();
+      return 0;
+    }
+
+    if (my_decimal2int(E_DEC_FATAL_ERROR, &tmp, unsigned_flag, &res) &
+        E_DEC_OVERFLOW)
+      my_error(ER_WARN_DATA_OUT_OF_RANGE, MYF(0), name, 1);
+    return res;
+  }
+  
   longlong value=args[0]->val_int();
   longlong val2=args[1]->val_int();
   if ((null_value= (args[0]->null_value || args[1]->null_value)))

=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc	2008-10-20 09:16:47 +0000
+++ b/sql/item_subselect.cc	2008-11-26 14:36:11 +0000
@@ -1005,6 +1005,7 @@ Item_in_subselect::single_value_transfor
     Check that the right part of the subselect contains no more than one
     column. E.g. in SELECT 1 IN (SELECT * ..) the right part is (SELECT * ...)
   */
+  // psergey: duplicated_subselect_card_check
   if (select_lex->item_list.elements > 1)
   {
     my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
@@ -1362,6 +1363,7 @@ Item_in_subselect::row_value_transformer
 
   DBUG_ENTER("Item_in_subselect::row_value_transformer");
 
+  // psergey: duplicated_subselect_card_check
   if (select_lex->item_list.elements != left_expr->cols())
   {
     my_error(ER_OPERAND_COLUMNS, MYF(0), left_expr->cols());
@@ -1696,6 +1698,8 @@ Item_in_subselect::select_in_like_transf
     In some optimisation cases we will not need this Item_in_optimizer
     object, but we can't know it here, but here we need address correct
     reference on left expresion.
+
+    //psergey: he means confluent cases like "... IN (SELECT 1)"
   */
   if (!optimizer)
   {
@@ -1896,7 +1900,11 @@ bool Item_in_subselect::init_left_expr_c
   bool use_result_field= FALSE;
 
   outer_join= unit->outer_select()->join;
-  if (!outer_join || !outer_join->tables)
+  /*
+    An IN predicate might be evaluated in a query for which all tables have
+    been optimzied away.
+  */ 
+  if (!outer_join || !outer_join->tables || !outer_join->tables_list)
     return TRUE;
   /*
     If we use end_[send | write]_group to handle complete rows of the outer
@@ -2218,11 +2226,6 @@ int subselect_single_select_engine::exec
     SELECT_LEX_UNIT *unit= select_lex->master_unit();
 
     unit->set_limit(unit->global_parameters);
-    if (join->flatten_subqueries())
-    {
-      thd->is_fatal_error= TRUE;
-      DBUG_RETURN(1);
-    }
     if (join->optimize())
     {
       thd->where= save_where;
@@ -3110,11 +3113,54 @@ bool subselect_hash_sj_engine::init_perm
   KEY_PART_INFO *cur_key_part= tmp_key->key_part;
   store_key **ref_key= tab->ref.key_copy;
   uchar *cur_ref_buff= tab->ref.key_buff;
+
+  /*
+    Create an artificial condition to post-filter those rows matched by index
+    lookups that cannot be distinguished by the index lookup procedure, e.g.
+    because of truncation. Prepared statements execution requires that
+    fix_fields is called for every execution. In order to call fix_fields we
+    need to create a Name_resolution_context and a corresponding TABLE_LIST
+    for the temporary table for the subquery, so that all column references
+    to the materialized subquery table can be resolved correctly.
+  */
+  DBUG_ASSERT(cond == NULL);
+  if (!(cond= new Item_cond_and))
+    DBUG_RETURN(TRUE);
+  /*
+    Table reference for tmp_table that is used to resolve column references
+    (Item_fields) to columns in tmp_table.
+  */
+  TABLE_LIST *tmp_table_ref;
+  if (!(tmp_table_ref= (TABLE_LIST*) thd->calloc(sizeof(TABLE_LIST))))
+    DBUG_RETURN(TRUE);
+
+  tmp_table_ref->init_one_table(NULL, 0, "materialized subselect", 22,
+                                "materialized subselect", TL_READ);
+  tmp_table_ref->table= tmp_table;
+
+  /* Name resolution context for all tmp_table columns created below. */
+  Name_resolution_context *context= new Name_resolution_context;
+  context->init();
+  context->first_name_resolution_table=
+    context->last_name_resolution_table= tmp_table_ref;
   
   for (uint i= 0; i < tmp_key_parts; i++, cur_key_part++, ref_key++)
   {
-    tab->ref.items[i]= item_in->left_expr->element_index(i);
+    Item_func_eq *eq_cond; /* New equi-join condition for the current column. */
+    /* Item for the corresponding field from the materialized temp table. */
+    Item_field *right_col_item;
     int null_count= test(cur_key_part->field->real_maybe_null());
+    tab->ref.items[i]= item_in->left_expr->element_index(i);
+
+    if (!(right_col_item= new Item_field(thd, context, cur_key_part->field)) ||
+        !(eq_cond= new Item_func_eq(tab->ref.items[i], right_col_item)) ||
+        ((Item_cond_and*)cond)->add(eq_cond))
+    {
+      delete cond;
+      cond= NULL;
+      DBUG_RETURN(TRUE);
+    }
+
     *ref_key= new store_key_item(thd, cur_key_part->field,
                                  /* TODO:
                                     the NULL byte is taken into account in
@@ -3131,6 +3177,9 @@ bool subselect_hash_sj_engine::init_perm
   tab->ref.key_err= 1;
   tab->ref.key_parts= tmp_key_parts;
 
+  if (cond->fix_fields(thd, &cond))
+    DBUG_RETURN(TRUE);
+
   DBUG_RETURN(FALSE);
 }
 
@@ -3150,6 +3199,12 @@ bool subselect_hash_sj_engine::init_runt
     the subquery if not yet created.
   */
   materialize_engine->prepare();
+  /*
+    Repeat name resolution for 'cond' since cond is not part of any
+    clause of the query, and it is not 'fixed' during JOIN::prepare.
+  */
+  if (cond && !cond->fixed && cond->fix_fields(thd, &cond))
+    return TRUE;
   /* Let our engine reuse this query plan for materialization. */
   materialize_join= materialize_engine->join;
   materialize_join->change_result(result);
@@ -3207,9 +3262,8 @@ int subselect_hash_sj_engine::exec()
     int res= 0;
     SELECT_LEX *save_select= thd->lex->current_select;
     thd->lex->current_select= materialize_engine->select_lex;
-    if ((res= materialize_join->flatten_subqueries()) || 
-        (res= materialize_join->optimize()))
-      goto err;
+    if ((res= materialize_join->optimize()))
+      goto err; /* purecov: inspected */
     materialize_join->exec();
     if ((res= test(materialize_join->error || thd->is_fatal_error)))
       goto err;

=== modified file 'sql/item_subselect.h'
--- a/sql/item_subselect.h	2008-05-01 03:53:36 +0000
+++ b/sql/item_subselect.h	2008-11-10 18:36:50 +0000
@@ -36,10 +36,21 @@ class Item_subselect :public Item_result
 public:
   /* thread handler, will be assigned in fix_fields only */
   THD *thd;
-  /* substitution instead of subselect in case of optimization */
+  /* 
+    Used inside Item_subselect::fix_fields() according to this scenario:
+      > Item_subselect::fix_fields
+        > engine->prepare
+          > child_join->prepare
+            (Here we realize we need to do the rewrite and set
+             substitution= some new Item, eg. Item_in_optimizer )
+          < child_join->prepare
+        < engine->prepare
+        *ref= substitution;
+      < Item_subselect::fix_fields
+  */
   Item *substitution;
-  /* unit of subquery */
 public:
+  /* unit of subquery */
   st_select_lex_unit *unit;
 protected:
   /* engine that perform execution of subselect (single select or union) */
@@ -303,6 +314,17 @@ public:
      - (TABLE_LIST*)1 if the predicate is in the WHERE.
   */
   TABLE_LIST *expr_join_nest;
+  /*
+    Types of left_expr and subquery's select list allow to perform subquery
+    materialization. Currently, we set this to FALSE when it as well could
+    be TRUE. This is to be properly addressed with fix for BUG#36752.
+  */
+  bool types_allow_materialization;
+
+  /* 
+    Same as above, but they also allow to scan the materialized table. 
+  */
+  bool sjm_scan_allowed;
 
   /* The method chosen to execute the IN predicate.  */
   enum enum_exec_method {

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2008-12-19 14:59:10 +0000
+++ b/sql/mysql_priv.h	2009-01-06 19:37:13 +0000
@@ -392,7 +392,6 @@ enum open_table_mode
 
 #define DISK_SEEK_PROP_COST ((double)0.1/BLOCKS_IN_AVG_SEEK)
 
-
 /**
   Number of rows in a reference table when refereed through a not unique key.
   This value is only used when we don't know anything about the key
@@ -400,6 +399,12 @@ enum open_table_mode
 */
 #define MATCHING_ROWS_IN_OTHER_TABLE 10
 
+/*
+  Subquery materialization-related constants
+*/
+#define HEAP_TEMPTABLE_LOOKUP_COST 0.05
+#define DISK_TEMPTABLE_LOOKUP_COST 1.0
+
 /** Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used). */
 #define KEY_DEFAULT_PACK_LENGTH 8
 
@@ -570,7 +575,7 @@ enum open_table_mode
 #define OPTIMIZER_SWITCH_NO_MATERIALIZATION 1
 #define OPTIMIZER_SWITCH_NO_SEMIJOIN 2
 #define OPTIMIZER_SWITCH_NO_LOOSE_SCAN 4
-
+#define OPTIMIZER_SWITCH_NO_FIRSTMATCH 8
 
 /*
   Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
@@ -1849,6 +1854,7 @@ void TEST_filesort(SORT_FIELD *sortorder
 void print_plan(JOIN* join,uint idx, double record_count, double read_time,
                 double current_read_time, const char *info);
 void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array);
+void print_sjm(SJ_MATERIALIZATION_INFO *sjm);
 #define EXTRA_DEBUG_DUMP_TABLE_LISTS
 #ifdef EXTRA_DEBUG_DUMP_TABLE_LISTS
 void dump_TABLE_LIST_graph(SELECT_LEX *select_lex, TABLE_LIST* tl);

=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc	2008-12-19 14:59:10 +0000
+++ b/sql/mysqld.cc	2009-01-06 19:37:13 +0000
@@ -329,7 +329,7 @@ TYPELIB sql_mode_typelib= { array_elemen
 
 static const char *optimizer_switch_names[]=
 {
-  "no_materialization", "no_semijoin", "no_loosescan",
+  "no_materialization", "no_semijoin", "no_loosescan", "no_firstmatch",
   NullS
 };
 
@@ -339,6 +339,7 @@ static const unsigned int optimizer_swit
   /*no_materialization*/          18,
   /*no_semijoin*/                 11,
   /*no_loosescan*/                12,
+  /*no_firstmatch*/               13
 };
 
 TYPELIB optimizer_switch_typelib= { array_elements(optimizer_switch_names)-1,"",

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2008-12-16 11:29:22 +0000
+++ b/sql/opt_range.cc	2008-12-31 13:49:36 +0000
@@ -671,6 +671,11 @@ public:
   */
   bool using_real_indexes;
   
+  /*
+    Aggressively remove "scans" that do not have conditions on first
+    keyparts. Such scans are usable when doing partition pruning but not
+    regular range optimization.
+  */
   bool remove_jump_scans;
   
   /*

=== modified file 'sql/opt_range.h'
--- a/sql/opt_range.h	2008-08-25 18:23:27 +0000
+++ b/sql/opt_range.h	2008-12-27 02:32:25 +0000
@@ -108,7 +108,11 @@ class QUICK_RANGE :public Sql_alloc {
 
   4. Delete the select:
     delete quick;
-
+  
+  NOTE 
+    quick select doesn't use Sql_alloc/MEM_ROOT allocation because "range
+    checked for each record" functionality may create/destroy
+    O(#records_in_some_table) quick selects during query execution.
 */
 
 class QUICK_SELECT_I

=== modified file 'sql/records.h'
--- a/sql/records.h	2008-09-12 09:09:27 +0000
+++ b/sql/records.h	2008-10-31 18:53:23 +0000
@@ -25,6 +25,7 @@ class handler;
 struct TABLE;
 class THD;
 class SQL_SELECT;
+class Copy_field;
 
 /**
   A context for reading through a single table using a chosen access method:
@@ -60,7 +61,13 @@ struct READ_RECORD
   uchar	*cache,*cache_pos,*cache_end,*read_positions;
   struct st_io_cache *io_cache;
   bool print_error, ignore_not_found_rows;
-  struct st_join_table *do_insideout_scan;
+
+  /* 
+    SJ-Materialization runtime may need to read fields from the materialized
+    table and unpack them into original table fields:
+  */
+  Copy_field *copy_field;
+  Copy_field *copy_field_end;
 
 public:
   READ_RECORD() {}
@@ -74,3 +81,4 @@ void init_read_record_idx(READ_RECORD *i
 void end_read_record(READ_RECORD *info);
 
 #endif /* SQL_RECORDS_H */
+

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2008-12-19 14:59:10 +0000
+++ b/sql/sql_base.cc	2009-01-06 19:37:13 +0000
@@ -3650,9 +3650,6 @@ int open_tables(THD *thd, TABLE_LIST **s
   */
   for (tables= *start; tables ;tables= tables->next_global)
   {
-    DBUG_PRINT("tcache", ("opening table: '%s'.'%s'  item: %p",
-                          tables->db, tables->table_name, tables));
-
     safe_to_ignore_table= FALSE;
 
     /*
@@ -3698,6 +3695,8 @@ int open_tables(THD *thd, TABLE_LIST **s
       }
       DBUG_RETURN(-1);
     }
+    DBUG_PRINT("tcache", ("opening table: '%s'.'%s'  item: %p",
+                          tables->db, tables->table_name, tables)); //psergey: invalid read of size 1 here
     (*counter)++;
 
     /* Not a placeholder: must be a base table or a view. Let us open it. */
@@ -6530,7 +6529,14 @@ int setup_wild(THD *thd, TABLE_LIST *tab
     /* make * substituting permanent */
     SELECT_LEX *select_lex= thd->lex->current_select;
     select_lex->with_wild= 0;
-    select_lex->item_list= fields;
+
+    /*
+      The assignment below is translated to memcpy() call (at least on some
+      platforms). memcpy() expects that source and destination areas do not
+      overlap. That problem was detected by valgrind.
+    */
+    if (&select_lex->item_list != &fields)
+      select_lex->item_list= fields;
 
     thd->restore_active_arena(arena, &backup);
   }

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2008-12-19 14:59:10 +0000
+++ b/sql/sql_class.h	2009-01-06 19:37:13 +0000
@@ -2812,6 +2812,67 @@ public:
   bool send_data(List<Item> &items);
 };
 
+struct st_table_ref;
+
+
+/*
+  Optimizer and executor structure for the materialized semi-join info. This
+  structure contains
+   - The sj-materialization temporary table
+   - Members needed to make index lookup or a full scan of the temptable.
+*/
+class SJ_MATERIALIZATION_INFO : public Sql_alloc
+{
+public:
+  /* Optimal join sub-order */
+  struct st_position *positions;
+
+  uint tables; /* Number of tables in the sj-nest */
+
+  /* Expected #rows in the materialized table */
+  double rows;
+
+  /* 
+    Cost to materialize - execute the sub-join and write rows into temp.table
+  */
+  COST_VECT materialization_cost;
+
+  /* Cost to make one lookup in the temptable */
+  COST_VECT lookup_cost;
+  
+  /* Cost of scanning the materialized table */
+  COST_VECT scan_cost;
+
+  /* --- Execution structures ---------- */
+  
+  /*
+    TRUE <=> This structure is used for execution. We don't necessarily pick
+    sj-materialization, so some of SJ_MATERIALIZATION_INFO structures are not
+    used by materialization
+  */
+  bool is_used;
+  
+  bool materialized; /* TRUE <=> materialization already performed */
+  /*
+    TRUE  - the temptable is read with full scan
+    FALSE - we use the temptable for index lookups
+  */
+  bool is_sj_scan; 
+  
+  /* The temptable and its related info */
+  TMP_TABLE_PARAM sjm_table_param;
+  List<Item> sjm_table_cols;
+  TABLE *table;
+
+  /* Structure used to make index lookups */
+  struct st_table_ref *tab_ref;
+  Item *in_equality; /* See create_subq_in_equalities() */
+
+  Item *join_cond; /* See comments in make_join_select() */
+  Copy_field *copy_field; /* Needed for SJ_Materialization scan */
+};
+
+
 /* Structs used when sorting */
 
 typedef struct st_sort_field {

=== modified file 'sql/sql_join_cache.cc'
--- a/sql/sql_join_cache.cc	2008-12-11 00:21:13 +0000
+++ b/sql/sql_join_cache.cc	2008-12-22 19:03:25 +0000
@@ -67,7 +67,6 @@ uint add_flag_field_to_join_cache(uchar
   copy->type= 0;
   copy->field= 0;
   copy->referenced_field_no= 0;
-  copy->get_rowid= NULL;
   (*field)++;
   return length;    
 }
@@ -123,7 +122,6 @@ uint add_table_data_fields_to_join_cache
       }
       copy->field= *fld_ptr;
       copy->referenced_field_no= 0;
-      copy->get_rowid= NULL;
       copy++;
       (*field_cnt)++;
       used_fields--;
@@ -350,21 +348,13 @@ void JOIN_CACHE:: create_remaining_field
                                                  &copy, &copy_ptr);
   
     /* SemiJoinDuplicateElimination: allocate space for rowid if needed */
-    if (tab->rowid_keep_flags & JOIN_TAB::KEEP_ROWID)
+    if (tab->keep_current_rowid)
     {
       copy->str= table->file->ref;
       copy->length= table->file->ref_length;
       copy->type= 0;
       copy->field= 0;
       copy->referenced_field_no= 0;
-      copy->get_rowid= NULL;
-      if (tab->rowid_keep_flags & JOIN_TAB::CALL_POSITION)
-      {
-        /* We will need to call h->position(): */
-        copy->get_rowid= tab->table;
-        /* And those after us won't have to: */
-        tab->rowid_keep_flags &=  ~((int)JOIN_TAB::CALL_POSITION);
-      }
       length+= copy->length;
       data_field_count++;
       copy++;
@@ -986,12 +976,6 @@ uint JOIN_CACHE::write_record_data(uchar
     }
     else
     {
-      if (copy->get_rowid)
-      {
-        /* SemiJoinDuplicateElimination: get the rowid into table->ref */
-        copy->get_rowid->file->position(copy->get_rowid->record[0]);
-      }
-
       switch (copy->type) {
       case CACHE_VARSTR1:
         /* Copy the significant part of the short varstring field */ 
@@ -1670,6 +1654,9 @@ enum_nested_loop_state JOIN_CACHE_BNL::j
   info= &join_tab->read_record;
   do
   {
+    if (join_tab->keep_current_rowid)
+      join_tab->table->file->position(join_tab->table->record[0]);
+
     if (join->thd->killed)
     {
       /* The user has aborted the execution of the query */
@@ -2168,6 +2155,8 @@ enum_nested_loop_state JOIN_CACHE_BKA::j
       rc= NESTED_LOOP_KILLED; 
       goto finish;
     }
+    if (join_tab->keep_current_rowid)
+      join_tab->table->file->position(join_tab->table->record[0]);
     /* 
       If only the first match is needed and it has been already found 
       for the associated partial join record then the returned candidate

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2008-12-19 14:59:10 +0000
+++ b/sql/sql_lex.h	2009-01-06 19:37:13 +0000
@@ -821,7 +821,7 @@ public:
   }
 
   void clear_index_hints(void) { index_hints= NULL; }
-
+  bool is_part_of_union() { return master_unit()->is_union(); }
 private:  
   /* current index hint kind. used in filling up index_hints */
   enum index_hint_type current_index_hint_type;

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2008-12-16 11:29:22 +0000
+++ b/sql/sql_select.cc	2008-12-31 13:49:36 +0000
@@ -54,6 +54,7 @@ struct st_sargable_param;
 static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
 static bool make_join_statistics(JOIN *join, TABLE_LIST *leaves, COND *conds,
 				 DYNAMIC_ARRAY *keyuse);
+static bool optimize_semijoin_nests(JOIN *join, table_map all_table_map);
 static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
                                 JOIN_TAB *join_tab,
                                 uint tables, COND *conds,
@@ -64,11 +65,11 @@ static int sort_keyuse(KEYUSE *a,KEYUSE
 static void set_position(JOIN *join,uint index,JOIN_TAB *table,KEYUSE *key);
 static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
 			       table_map used_tables);
-static bool choose_plan(JOIN *join,table_map join_tables);
-
-static void best_access_path(JOIN *join, JOIN_TAB *s, THD *thd,
-                             table_map remaining_tables, uint idx,
-                             double record_count, double read_time);
+static bool choose_plan(JOIN *join, table_map join_tables);
+static void best_access_path(JOIN *join, JOIN_TAB *s, 
+                             table_map remaining_tables, uint idx, 
+                             bool disable_jbuf, double record_count,
+                             POSITION *pos, POSITION *loose_scan_pos);
 static void optimize_straight_join(JOIN *join, table_map join_tables);
 static bool greedy_search(JOIN *join, table_map remaining_tables,
                              uint depth, uint prune_level);
@@ -78,8 +79,9 @@ static bool best_extension_by_limited_se
                                              double read_time, uint depth,
                                              uint prune_level);
 static uint determine_search_depth(JOIN* join);
-static int join_tab_cmp(const void* ptr1, const void* ptr2);
-static int join_tab_cmp_straight(const void* ptr1, const void* ptr2);
+static int join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2);
+static int join_tab_cmp_straight(const void *dummy, const void* ptr1, const void* ptr2);
+static int join_tab_cmp_embedded_first(const void *emb, const void* ptr1, const void *ptr2);
 /*
   TODO: 'find_best' is here only temporarily until 'greedy_search' is
   tested and approved.
@@ -95,7 +97,9 @@ static store_key *get_store_key(THD *thd
 				uint maybe_null);
 static bool make_simple_join(JOIN *join,TABLE *tmp_table);
 static void make_outerjoin_info(JOIN *join);
-static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item);
+static Item*
+make_cond_after_sjm(Item *root_cond, Item *cond, table_map tables, table_map sjm_tables);
+static bool make_join_select(JOIN *join, Item *item);
 static bool make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after);
 static bool only_eq_ref_tables(JOIN *join, ORDER *order, table_map tables);
 static void update_depend_map(JOIN *join);
@@ -122,9 +126,13 @@ static uint build_bitmap_for_nested_join
                                           uint first_unused);
 
 static 
-void advance_sj_state(const table_map remaining_tables, const JOIN_TAB *tab);
+void advance_sj_state(JOIN *join, const table_map remaining_tables, 
+                      const JOIN_TAB *s, uint idx, 
+                      double *current_record_count, double *current_read_time,
+                      POSITION *loose_scan_pos);
+
 static void restore_prev_sj_state(const table_map remaining_tables, 
-                                  const JOIN_TAB *tab);
+                                  const JOIN_TAB *tab, uint idx);
 
 static COND *optimize_cond(JOIN *join, COND *conds,
                            List<TABLE_LIST> *join_list,
@@ -164,6 +172,7 @@ static int join_read_const_table(JOIN_TA
 static int join_read_system(JOIN_TAB *tab);
 static int join_read_const(JOIN_TAB *tab);
 static int join_read_key(JOIN_TAB *tab);
+static int join_read_key2(JOIN_TAB *tab, TABLE *table, TABLE_REF *table_ref);
 static int join_read_always_key(JOIN_TAB *tab);
 static int join_read_last_key(JOIN_TAB *tab);
 static int join_no_more_records(READ_RECORD *info);
@@ -207,7 +216,7 @@ static int remove_dup_with_hash_index(TH
 				      uint field_count, Field **first_field,
 
 				      ulong key_length,Item *having);
-static bool cmp_buffer_with_ref(JOIN_TAB *tab);
+static bool cmp_buffer_with_ref(THD *thd, TABLE *table, TABLE_REF *tab_ref);
 static bool setup_new_fields(THD *thd, List<Item> &fields,
 			     List<Item> &all_fields, ORDER *new_order);
 static ORDER *create_distinct_group(THD *thd, Item **ref_pointer_array,
@@ -240,24 +249,31 @@ void select_describe(JOIN *join, bool ne
 			    bool distinct, const char *message=NullS);
 static Item *remove_additional_cond(Item* conds);
 static void add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab);
-static bool test_if_ref(COND *root_cond, 
+static bool test_if_ref(Item *root_cond, 
                         Item_field *left_item,Item *right_item);
-static bool replace_where_subcondition(JOIN *join, TABLE_LIST *emb_nest, 
+static bool replace_where_subcondition(JOIN *join, Item **expr, 
                                        Item *old_cond, Item *new_cond,
                                        bool do_fix_fields);
+void get_partial_join_cost(JOIN *join, uint idx, double *read_time_arg,
+                           double *record_count_arg);
+static uint make_join_orderinfo(JOIN *join);
+static int
+join_read_record_no_init(JOIN_TAB *tab);
+static
+bool subquery_types_allow_materialization(THD *thd, 
+                                          Item_in_subselect *in_subs,
+                                          bool *scan_allowed);
+int do_sj_reset(SJ_TMP_TABLE *sj_tbl);
+TABLE *create_duplicate_weedout_tmp_table(THD *thd, uint uniq_tuple_length_arg,
+                                          SJ_TMP_TABLE *sjtbl);
+inline bool optimizer_flag(THD *thd, uint flag)
+{ 
+  return (thd->variables.optimizer_switch & flag);
+}
 
-/*
-  This is used to mark equalities that were made from i-th IN-equality.
-  We limit semi-join InsideOut optimization to handling max 64 inequalities,
-  The following variable occupies 64 addresses.
-*/
-const char *subq_sj_cond_name=
-  "0123456789ABCDEF0123456789abcdef0123456789ABCDEF0123456789abcdef-sj-cond";
+Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
+                            bool *inherited_fl);
 
-static bool bitmap_covers(const table_map x, const table_map y)
-{
-  return !test(y & ~x);
-}
 
 /**
   This handles SELECT with and without UNION.
@@ -550,145 +566,157 @@ JOIN::prepare(Item ***rref_pointer_array
       DBUG_RETURN(-1);				/* purecov: inspected */
     thd->lex->allow_sum_func= save_allow_sum_func;
   }
+  
+  /*
+    If 
+      1) this join is inside a subquery (of any type except FROM-clause 
+         subquery) and
+      2) we aren't just normalizing a VIEW
+
+    Then perform early unconditional subquery transformations:
+     - Convert subquery predicate into semi-join, or
+     - Mark the subquery for execution using materialization, or
+     - Perform IN->EXISTS transformation, or
+     - Perform more/less ALL/ANY -> MIN/MAX rewrite
+     - Substitute trivial scalar-context subquery with its value
 
-  if (!thd->lex->view_prepare_mode)
+    TODO: for PS, make the whole block execute only on the first execution
+  */
+  Item_subselect *subselect;
+  if (!thd->lex->view_prepare_mode &&                    // (1)
+      (subselect= select_lex->master_unit()->item))      // (2)
   {
-    Item_subselect *subselect;
     Item_in_subselect *in_subs= NULL;
+    if (subselect->substype() == Item_subselect::IN_SUBS)
+      in_subs= (Item_in_subselect*)subselect;
+    DBUG_PRINT("info", ("Checking if subq can be converted to semi-join"));
     /*
-      Are we in a subquery predicate?
-      TODO: the block below will be executed for every PS execution without need.
+      Check if we're in subquery that is a candidate for flattening into a
+      semi-join (which is done in flatten_subqueries()). The
+      requirements are:
+        1. Subquery predicate is an IN/=ANY subq predicate
+        2. Subquery is a single SELECT (not a UNION)
+        3. Subquery does not have GROUP BY or ORDER BY
+        4. Subquery does not use aggregate functions or HAVING
+        5. Subquery predicate is at the AND-top-level of ON/WHERE clause
+        6. We are not in a subquery of a single table UPDATE/DELETE that 
+             doesn't have a JOIN (TODO: We should handle this at some
+             point by switching to multi-table UPDATE/DELETE)
+        7. We're not in a confluent table-less subquery, like "SELECT 1".
+        8. No execution method was already chosen (by a prepared statement)
+        9. Parent select is not a confluent table-less select
+        10. Neither parent nor child select have STRAIGHT_JOIN option.
     */
-    if ((subselect= select_lex->master_unit()->item))
-    {
-      bool do_semijoin= !test(thd->variables.optimizer_switch &
-                              OPTIMIZER_SWITCH_NO_SEMIJOIN);
-      if (subselect->substype() == Item_subselect::IN_SUBS)
-        in_subs= (Item_in_subselect*)subselect;
+    if (!optimizer_flag(thd, OPTIMIZER_SWITCH_NO_SEMIJOIN) &&
+        in_subs &&                                                    // 1
+        !select_lex->is_part_of_union() &&                            // 2
+        !select_lex->group_list.elements && !order &&                 // 3
+        !having && !select_lex->with_sum_func &&                      // 4
+        thd->thd_marker.emb_on_expr_nest &&                           // 5
+        select_lex->outer_select()->join &&                           // 6
+        select_lex->master_unit()->first_select()->leaf_tables &&     // 7
+        in_subs->exec_method == Item_in_subselect::NOT_TRANSFORMED && // 8
+        select_lex->outer_select()->leaf_tables &&                    // 9
+        !((select_options | select_lex->outer_select()->join->select_options)
+          & SELECT_STRAIGHT_JOIN))                                    // 10
+    {
+      DBUG_PRINT("info", ("Subquery is semi-join conversion candidate"));
+      in_subs->types_allow_materialization= 
+        subquery_types_allow_materialization(thd, in_subs,
+                                             &in_subs->sjm_scan_allowed);
+
+      if (thd->stmt_arena->state != Query_arena::PREPARED)
+      {
+        SELECT_LEX *current= thd->lex->current_select;
+        thd->lex->current_select= current->return_after_parsing();
+        char const *save_where= thd->where;
+        thd->where= "IN/ALL/ANY subquery";
+        
+        bool failure= !in_subs->left_expr->fixed &&
+                       in_subs->left_expr->fix_fields(thd, 
+                                                      &in_subs->left_expr);
+        thd->lex->current_select= current;
+        thd->where= save_where;
+        in_subs->emb_on_expr_nest= thd->thd_marker.emb_on_expr_nest;
+        if (failure)
+          DBUG_RETURN(-1); /* purecov: deadcode */
+        /*
+          Check if the left and right expressions have the same # of
+          columns, i.e. we don't have a case like 
+            (oe1, oe2) IN (SELECT ie1, ie2, ie3 ...)
 
-      DBUG_PRINT("info", ("Checking if subq can be converted to semi-join"));
-      /*
-        Check if we're in subquery that is a candidate for flattening into a
-        semi-join (which is done done in flatten_subqueries()). The
-        requirements are:
-          1. Subquery predicate is an IN/=ANY subq predicate
-          2. Subquery is a single SELECT (not a UNION)
-          3. Subquery does not have GROUP BY or ORDER BY
-          4. Subquery does not use aggregate functions or HAVING
-          5. Subquery predicate is at the AND-top-level of ON/WHERE clause
-          6. No execution method was already chosen (by a prepared statement).
-          7. Parent SELECT is not a confluent "SELECT ... FROM DUAL" w/o tables
-          (*). We are not in a subquery of a single table UPDATE/DELETE that 
-               doesn't have a JOIN (TODO: We should handle this at some
-               point by switching to multi-table UPDATE/DELETE)
-
-          (**). We're not in a confluent table-less subquery, like
-                "SELECT 1". 
-      */
-      if (in_subs &&                                                    // 1
-          !select_lex->master_unit()->first_select()->next_select() &&  // 2
-          !select_lex->group_list.elements && !order &&                 // 3
-          !having && !select_lex->with_sum_func &&                      // 4
-          thd->thd_marker.emb_on_expr_nest &&                           // 5
-          select_lex->outer_select()->join &&                           // (*)
-          select_lex->master_unit()->first_select()->leaf_tables &&     // (**) 
-          do_semijoin &&
-          in_subs->exec_method == Item_in_subselect::NOT_TRANSFORMED && // 6
-          select_lex->outer_select()->leaf_tables)                     // 7
-      {
-        DBUG_PRINT("info", ("Subquery is semi-join conversion candidate"));
-
-        if (thd->stmt_arena->state != Query_arena::PREPARED)
-        {
-          SELECT_LEX *current= thd->lex->current_select;
-          thd->lex->current_select= current->return_after_parsing();
-          char const *save_where= thd->where;
-          thd->where= "IN/ALL/ANY subquery";
-          
-          bool failure= !in_subs->left_expr->fixed &&
-                         in_subs->left_expr->fix_fields(thd, 
-                                                        &in_subs->left_expr);
-          thd->lex->current_select= current;
-          thd->where= save_where;
-          in_subs->emb_on_expr_nest= thd->thd_marker.emb_on_expr_nest;
-          if (failure)
-            DBUG_RETURN(-1);
-          /*
-            Check that the right part of the subselect contains no more than one
-            column. E.g. in SELECT 1 IN (SELECT * ..) the right part is (SELECT * ...)
-          */
-          if (subselect->substype() == Item_subselect::IN_SUBS &&
-             (select_lex->item_list.elements != 
-              ((Item_in_subselect*)subselect)->left_expr->cols()))
-          {
-            my_error(ER_OPERAND_COLUMNS, MYF(0), ((Item_in_subselect*)subselect)->left_expr->cols());
-            DBUG_RETURN(-1);
-          }
+          TODO why do we have this duplicated in IN->EXISTS transformers?
+          psergey-todo: fix these: grep for duplicated_subselect_card_check
+        */
+        if (select_lex->item_list.elements != in_subs->left_expr->cols())
+        {
+          my_error(ER_OPERAND_COLUMNS, MYF(0), in_subs->left_expr->cols());
+          DBUG_RETURN(-1);
         }
-
-        /* Register the subquery for further processing */
-        select_lex->outer_select()->join->sj_subselects.append(thd->mem_root, in_subs);
-        in_subs->expr_join_nest= thd->thd_marker.emb_on_expr_nest;
       }
-      else
-      {
-        DBUG_PRINT("info", ("Subquery can't be converted to semi-join"));
-        bool do_materialize= !test(thd->variables.optimizer_switch &
-                                   OPTIMIZER_SWITCH_NO_MATERIALIZATION);
-        /*
-          Check if the subquery predicate can be executed via materialization.
-          The required conditions are:
-          1. Subquery predicate is an IN/=ANY subq predicate
-          2. Subquery is a single SELECT (not a UNION)
-          3. Subquery is not a table-less query. In this case there is no
-             point in materializing.
+
+      /* Register the subquery for further processing */
+      select_lex->outer_select()->join->sj_subselects.append(thd->mem_root, in_subs);
+      in_subs->expr_join_nest= thd->thd_marker.emb_on_expr_nest;
+    }
+    else
+    {
+      DBUG_PRINT("info", ("Subquery can't be converted to semi-join"));
+      /*
+        Check if the subquery predicate can be executed via materialization.
+        The required conditions are:
+        1. Subquery predicate is an IN/=ANY subq predicate
+        2. Subquery is a single SELECT (not a UNION)
+        3. Subquery is not a table-less query. In this case there is no
+           point in materializing.
           3A The upper query is not a confluent SELECT ... FROM DUAL. We
              can't do materialization for SELECT .. FROM DUAL because it
              does not call setup_subquery_materialization(). We could make 
              SELECT ... FROM DUAL call that function but that doesn't seem
              to be the case that is worth handling.
-          4. Subquery predicate is a top-level predicate
-             (this implies it is not negated)
-             TODO: this is a limitation that should be lifeted once we
-             implement correct NULL semantics (WL#3830)
-          5. Subquery is non-correlated
-             TODO:
-             This is an overly restrictive condition. It can be extended to:
-             (Subquery is non-correlated ||
-              Subquery is correlated to any query outer to IN predicate ||
-              (Subquery is correlated to the immediate outer query &&
-               Subquery !contains {GROUP BY, ORDER BY [LIMIT],
-               aggregate functions}) && subquery predicate is not under "NOT IN"))
-          6. No execution method was already chosen (by a prepared statement).
-
-          (*) The subquery must be part of a SELECT statement. The current
-               condition also excludes multi-table update statements.
-
-          We have to determine whether we will perform subquery materialization
-          before calling the IN=>EXISTS transformation, so that we know whether to
-          perform the whole transformation or only that part of it which wraps
-          Item_in_subselect in an Item_in_optimizer.
-        */
-        if (do_materialize && 
-            in_subs  &&                                                   // 1
-            !select_lex->master_unit()->first_select()->next_select() &&  // 2
-            select_lex->master_unit()->first_select()->leaf_tables &&     // 3
-            thd->lex->sql_command == SQLCOM_SELECT &&                     // *
-            select_lex->outer_select()->leaf_tables)                      // 3A
-        {
-          if (in_subs->is_top_level_item() &&                             // 4
-              !in_subs->is_correlated &&                                  // 5
-              in_subs->exec_method == Item_in_subselect::NOT_TRANSFORMED) // 6
-            in_subs->exec_method= Item_in_subselect::MATERIALIZATION;
-        }
-
-        Item_subselect::trans_res trans_res;
-        if ((trans_res= subselect->select_transformer(this)) !=
-            Item_subselect::RES_OK)
-        {
-          select_lex->fix_prepare_information(thd, &conds, &having);
-          DBUG_RETURN((trans_res == Item_subselect::RES_ERROR));
-        }
+        4. Subquery predicate is a top-level predicate
+           (this implies it is not negated)
+           TODO: this is a limitation that should be lifted once we
+           implement correct NULL semantics (WL#3830)
+        5. Subquery is non-correlated
+           TODO:
+           This is an overly restrictive condition. It can be extended to:
+           (Subquery is non-correlated ||
+            Subquery is correlated to any query outer to IN predicate ||
+            (Subquery is correlated to the immediate outer query &&
+             Subquery !contains {GROUP BY, ORDER BY [LIMIT],
+             aggregate functions}) && subquery predicate is not under "NOT IN"))
+        6. No execution method was already chosen (by a prepared statement).
+
+        (*) The subquery must be part of a SELECT statement. The current
+             condition also excludes multi-table update statements.
+
+        We have to determine whether we will perform subquery materialization
+        before calling the IN=>EXISTS transformation, so that we know whether to
+        perform the whole transformation or only that part of it which wraps
+        Item_in_subselect in an Item_in_optimizer.
+      */
+      if (!optimizer_flag(thd, OPTIMIZER_SWITCH_NO_MATERIALIZATION)  && 
+          in_subs  &&                                                   // 1
+          !select_lex->is_part_of_union() &&                            // 2
+          select_lex->master_unit()->first_select()->leaf_tables &&     // 3
+          thd->lex->sql_command == SQLCOM_SELECT &&                     // *
+          select_lex->outer_select()->leaf_tables &&                    // 3A
+          subquery_types_allow_materialization(thd, in_subs, NULL))
+      {
+        // psergey-todo: duplicated_subselect_card_check: where it's done?
+        if (in_subs->is_top_level_item() &&                             // 4
+            !in_subs->is_correlated &&                                  // 5
+            in_subs->exec_method == Item_in_subselect::NOT_TRANSFORMED) // 6
+          in_subs->exec_method= Item_in_subselect::MATERIALIZATION;
+      }
+
+      Item_subselect::trans_res trans_res;
+      if ((trans_res= subselect->select_transformer(this)) !=
+          Item_subselect::RES_OK)
+      {
+        select_lex->fix_prepare_information(thd, &conds, &having);
+        DBUG_RETURN((trans_res == Item_subselect::RES_ERROR));
       }
     }
   }
@@ -825,6 +853,118 @@ err:
 
 
 /*
+  Check if subquery's compared types allow materialization.
+
+  SYNOPSIS
+    subquery_types_allow_materialization()
+      thd               Thread handle
+      in_subs           Subquery predicate
+      scan_allowed  OUT If the return value is TRUE: 
+                          indicates whether it is possible to use subquery
+                          materialization and scan the materialized table
+                        Else
+                          undefined
+  DESCRIPTION
+    This is a temporary fix for BUG#36752.
+    
+    There are two subquery materialization strategies:
+
+    1. Materialize and do index lookups in the materialized table. See 
+       BUG#36752 for description of restrictions we need to put on the
+       compared expressions.
+
+    2. Materialize and then do a full scan of the materialized table. At the
+       moment, this strategy's applicability criteria are even stricter than
+       in #1.
+
+       This is so because of the following: consider an uncorrelated subquery
+       
+       ...WHERE (ot1.col1, ot2.col2 ...) IN (SELECT ie1,ie2,... FROM it1 ...)
+
+       and a join order that could be used to do sjm-materialization: 
+          
+          SJM-Scan(it1, it1), ot1, ot2
+       
+       IN-equalities will be parts of conditions attached to the outer tables:
+
+         ot1:  ot1.col1 = ie1 AND ... (C1)
+         ot2:  ot1.col2 = ie2 AND ... (C2)
+       
+       besides those there may be additional references to ie1 and ie2
+       generated by equality propagation. The problem with evaluating C1 and
+       C2 is that ie{1,2} refer to subquery tables' columns, while we only have 
+       current value of materialization temptable. Our solution is to 
+        * require that all ie{N} are table column references. This allows 
+          to copy the values of materialization temptable columns to the
+          original table's columns (see setup_sj_materialization for more
+          details)
+        * require that compared columns have exactly the same type. This is
+          a temporary measure to avoid BUG#36752-type problems.
+
+  RETURN 
+    TRUE   Yes, subquery types allow materialization
+    FALSE  No, or this is an invalid subquery
+*/
+
+static 
+bool subquery_types_allow_materialization(THD *thd,  
+                                          Item_in_subselect *in_subs,
+                                          bool *scan_allowed)
+{
+  DBUG_ENTER("subquery_types_allow_materialization");
+  
+  /* Fix the left expression if it is not yet fixed */
+  if (!in_subs->left_expr->fixed)
+  {
+    SELECT_LEX *save_lex= thd->lex->current_select;
+    thd->lex->current_select= save_lex->outer_select();
+    char const *save_where= thd->where;
+    thd->where= "IN/ALL/ANY subquery";
+    bool res= in_subs->left_expr->fix_fields(thd, &in_subs->left_expr);
+    thd->where= save_where;
+    thd->lex->current_select=save_lex;
+    if (res)
+      DBUG_RETURN(FALSE);
+  }
+
+  List_iterator<Item> it(in_subs->unit->first_select()->item_list);
+  uint elements= in_subs->unit->first_select()->item_list.elements;
+  // psergey: duplicated_subselect_card_check
+  if (in_subs->left_expr->cols() != elements)
+    DBUG_RETURN(FALSE);
+  
+  bool all_are_fields= TRUE;
+  for (uint i= 0; i < elements; i++)
+  {
+    Item *outer= in_subs->left_expr->element_index(i);
+    Item *inner= it++;
+    all_are_fields &= (outer->real_item()->type() == Item::FIELD_ITEM && 
+                       inner->real_item()->type() == Item::FIELD_ITEM);
+    if (outer->result_type() != inner->result_type())
+      DBUG_RETURN(FALSE);
+    switch (outer->result_type()) {
+    case STRING_RESULT:
+      if (outer->is_datetime() != inner->is_datetime())
+        DBUG_RETURN(FALSE);
+
+      if (!(outer->collation.collation == inner->collation.collation 
+          /*&& outer->max_length <= inner->max_length */))
+        DBUG_RETURN(FALSE);
+    /*case INT_RESULT:
+      if (!(outer->unsigned_flag ^ inner->unsigned_flag))
+        DBUG_RETURN(FALSE); */
+    default:
+      ;/* suitable for materialization */
+    }
+  }
+  if (scan_allowed)
+    *scan_allowed= all_are_fields;
+  DBUG_PRINT("info",("subquery_types_allow_materialization: ok, allowed"));
+  DBUG_RETURN(TRUE);
+}
+
+
+/*
   Remove the predicates pushed down into the subquery
 
   SYNOPSIS
@@ -860,7 +1000,7 @@ void JOIN::remove_subq_pushed_predicates
       ((Item_func *)this->conds)->functype() == Item_func::EQ_FUNC &&
       ((Item_func *)conds)->arguments()[0]->type() == Item::REF_ITEM &&
       ((Item_func *)conds)->arguments()[1]->type() == Item::FIELD_ITEM &&
-      test_if_ref (this->conds, 
+      test_if_ref (this->conds,
                    (Item_field *)((Item_func *)conds)->arguments()[1],
                    ((Item_func *)conds)->arguments()[0]))
   {
@@ -907,8 +1047,6 @@ static void save_index_subquery_explain_
 }
 
 
-
-
 /*
   Check if the table's rowid is included in the temptable
 
@@ -966,10 +1104,6 @@ static bool sj_table_is_included(JOIN *j
 }
 
 
-TABLE *create_duplicate_weedout_tmp_table(THD *thd, uint uniq_tuple_length_arg,
-                                          SJ_TMP_TABLE *sjtbl);
-
-
 /*
   Setup the strategies to eliminate semi-join duplicates.
   
@@ -982,14 +1116,15 @@ TABLE *create_duplicate_weedout_tmp_tabl
                      be used.
 
   DESCRIPTION
-    Setup the strategies to eliminate semi-join duplicates. ATM there are 3
+    Setup the strategies to eliminate semi-join duplicates. ATM there are 4
     strategies:
 
     1. DuplicateWeedout (use of temptable to remove duplicates based on rowids
                          of row combinations)
     2. FirstMatch (pick only the 1st matching row combination of inner tables)
-    3. InsideOut (scanning the sj-inner table in a way that groups duplicates
+    3. LooseScan (scanning the sj-inner table in a way that groups duplicates
                   together and picking the 1st one)
+    4. SJ-Materialization.
     
     The join order has "duplicate-generating ranges", and every range is
     served by one strategy or a combination of FirstMatch with with some
@@ -1015,12 +1150,12 @@ TABLE *create_duplicate_weedout_tmp_tabl
 
        (1) - Prefix of OuterTables (those that participate in 
              IN-equality and/or are correlated with subquery) and outer 
-             Noncorrelated Tables.
+             Non-correlated tables.
        (2) - The handled range. The range starts with the first sj-inner
              table, and covers all sj-inner and outer tables 
-             Within the range,  Inner, Outer, outer Noncorrelated tables
+             Within the range,  Inner, Outer, outer non-correlated tables
              may follow in any order.
-       (3) - The suffix of outer Noncorrelated tables.
+       (3) - The suffix of outer non-correlated tables.
     
     FirstMatch strategy
     ~~~~~~~~~~~~~~~~~~~
@@ -1032,12 +1167,12 @@ TABLE *create_duplicate_weedout_tmp_tabl
       (1) - Prefix of outer and non-correlated tables
       (2) - The handled range, which may contain only inner and
             non-correlated tables.
-      (3) - The suffix of outer Noncorrelated tables.
+      (3) - The suffix of outer non-correlated tables.
 
-    InsideOut strategy 
+    LooseScan strategy 
     ~~~~~~~~~~~~~~~~~~
 
-     (ot|ct|nt) [ insideout_tbl (ot|nt|it)* it ]  (ot|nt)*
+     (ot|ct|nt) [ loosescan_tbl (ot|nt|it)* it ]  (ot|nt)*
      +--------+   +===========+ +=============+   +------+
         (1)           (2)          (3)              (4)
      
@@ -1045,7 +1180,7 @@ TABLE *create_duplicate_weedout_tmp_tabl
             all the non-trivially correlated outer tables. (non-trivially means
             that the correlation is not just through the IN-equality).
       
-      (2) - Inner table for which the InsideOut scan is performed.
+      (2) - Inner table for which the LooseScan scan is performed.
 
       (3) - The remainder of the duplicate-generating range. It is served by 
             application of FirstMatch strategy, with the exception that
@@ -1053,333 +1188,217 @@ TABLE *create_duplicate_weedout_tmp_tabl
 
       (4) - THe suffix of outer and outer non-correlated tables.
 
-    If several strategies are applicable, their relative priorities are:
-      1. InsideOut
-      2. FirstMatch 
-      3. DuplicateWeedout
-
-    This function walks over the join order and sets up the strategies by
-    setting appropriate members in join_tab structures.
+  
+  The choice between the strategies is made by the join optimizer (see
+  advance_sj_state() and fix_semijoin_strategies_for_picked_join_order()).
+  This function sets up all fields/structures/etc needed for execution except
+  for setup/initialization of semi-join materialization which is done in 
+  setup_sj_materialization() (todo: can't we move that to here also?)
 
   RETURN
     FALSE  OK 
     TRUE   Out of memory error
 */
 
-static
-int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, uint no_jbuf_after)
+int setup_semijoin_dups_elimination(JOIN *join, ulonglong options, 
+                                    uint no_jbuf_after)
 {
-  table_map cur_map= join->const_table_map | PSEUDO_TABLE_BITS;
-  enum sj_strategy_enum { 
-    SJ_STRATEGY_INVALID,
-    SJ_STRATEGY_INSIDEOUT,
-    SJ_STRATEGY_DUPS_WEEDOUT,
-    SJ_STRATEGY_DUPS_WEEDOUT_JBUF
-  };
-  struct {
-    /* 
-      0 - invalid (EOF marker), 
-      1 - InsideOut, 
-      2 - Temptable (maybe confluent),
-      3 - Temptable with join buffering
-    */
-    enum sj_strategy_enum strategy;
-    uint start_idx; /* Left range bound */
-    uint end_idx;   /* Right range bound */
-    /* 
-      For Temptable strategy: Bitmap of all outer and correlated tables from 
-      all involved join nests.
-    */
-    table_map outer_tables;
-  } dups_ranges [MAX_TABLES];
-
-  TABLE_LIST *emb_insideout_nest= NULL;
-  table_map emb_sj_map= 0;  /* A bitmap of sj-nests (that is, their sj-inner
-                               tables) whose ranges we're in */
-  table_map emb_outer_tables= 0; /* sj-outer tables for those sj-nests */
-  table_map range_start_map; /* table_map at current range start */
-  bool dealing_with_jbuf= FALSE; /* TRUE <=> table within cur range uses join buf */
-  int cur_range= 0;
   uint i;
-
+  THD *thd= join->thd;
   DBUG_ENTER("setup_semijoin_dups_elimination");
-  LINT_INIT(range_start_map); // protected by emb_sj_map
-  /*
-    First pass: locate the duplicate-generating ranges and pick the strategies.
-  */
+
   for (i= join->const_tables ; i < join->tables ; i++)
   {
-    JOIN_TAB *tab=join->join_tab+i;
-    TABLE *table=tab->table;
-    cur_map |= table->map;
-
-    if (tab->emb_sj_nest) // Encountered an sj-inner table
-    {
-      if (!emb_sj_map)
+    JOIN_TAB *tab=join->join_tab + i;
+    POSITION *pos= join->best_positions + i;
+    uint keylen, keyno;
+    switch (pos->sj_strategy) {
+      case SJ_OPT_MATERIALIZE:
+      case SJ_OPT_MATERIALIZE_SCAN:
+        /* Do nothing */
+        i += pos->n_sj_tables;
+        break;
+      case SJ_OPT_LOOSE_SCAN:
       {
-        dups_ranges[cur_range].start_idx= i;
-        range_start_map= cur_map & ~table->map;
-        /*
-          Remember if this is a possible start of range that is covered by
-          the InsideOut strategy (the reason that it is not covered could
-          be that it overlaps with anther semi-join's range. we don't
-          support InsideOut for joined ranges)
-        */
-        if (join->best_positions[i].insideout_key != MAX_KEY)
-          emb_insideout_nest= tab->emb_sj_nest;
-      }
-
-      emb_sj_map |= tab->emb_sj_nest->sj_inner_tables;
-      emb_outer_tables |= tab->emb_sj_nest->nested_join->sj_depends_on;
+        /* We jump from the last table to the first one */
+        tab->loosescan_match_tab= tab + pos->n_sj_tables - 1;
 
-      if (tab->emb_sj_nest != emb_insideout_nest)
-      {
-        /*
-          Two different semi-joins interleave. This cannot be handled by
-          InsideOut strategy.
-        */
-        emb_insideout_nest= NULL;
+        /* Calculate key length */
+        keylen= 0;
+        keyno= pos->loosescan_key;
+        for (uint kp=0; kp < pos->loosescan_parts; kp++)
+          keylen += tab->table->key_info[keyno].key_part[kp].store_length;
+
+        tab->loosescan_key_len= keylen;
+        if (pos->n_sj_tables > 1) 
+          tab[pos->n_sj_tables - 1].do_firstmatch= tab;
+        i += pos->n_sj_tables;
+        break;
       }
-    }
-
-    if (emb_sj_map) /* We're in duplicate-generating range */
-    {
-      if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) &&
-          tab->type == JT_ALL && tab->use_quick != 2 && !tab->first_inner &&
-          i <= no_jbuf_after && !dealing_with_jbuf)
+      case SJ_OPT_DUPS_WEEDOUT:
       {
         /*
-          This table uses join buffering, which makes use of FirstMatch or 
-          InsideOut strategies impossible for the current and (we assume) 
-          preceding duplicate-producing ranges.
-          That is, for the join order:
-
-              x x [ x  x]  x  [x x x]  x  [x x X*  x] x
-                  |     |     |     |          | \
-                  +-----+     +-----+          |  join buffering use
-                     r1          r2         we're here
-
-          we'll have to remove r1 and r2 and use duplicate-elimination
-          strategy that spans all the tables, starting from the very 1st
-          one.
-        */
-        dealing_with_jbuf= TRUE;
-        emb_insideout_nest= FALSE;
-
-        /* 
-          Absorb all preceding duplicate-eliminating ranges. Their strategies
-          do not matter: 
+          Check for join buffering. If there is one, move the first table
+          forwards, but do not destroy other duplicate elimination methods.
         */
-        for (int prev_range= 0; prev_range < cur_range; prev_range++)
+        uint first_table= i;
+        for (uint j= i; j < i + pos->n_sj_tables; j++)
         {
-          dups_ranges[cur_range].outer_tables |= 
-            dups_ranges[prev_range].outer_tables;
+          if (join->best_positions[j].use_join_buffer && j <= no_jbuf_after)
+          {
+            first_table= join->const_tables;
+            break;
+          }
         }
-        dups_ranges[0].start_idx= 0; /* Will need to start from the 1st table */
-        dups_ranges[0].outer_tables= dups_ranges[cur_range].outer_tables;
-        cur_range=  0;
-      }
 
-      /*
-        Check if we are at the end of duplicate-producing range. We are if
-
-        1. It's an InsideOut range (which presumes all correlated tables are
-           in the prefix), and all inner tables are in the join order prefix,
-           or
-        2. It's a DuplicateElimination range (possibly covering several
-           SJ-nests), and all inner, outer, and correlated tables of all 
-           sj-nests are in the join order prefix.
-      */
-      bool end_of_range= FALSE;
-      if (emb_insideout_nest && 
-          bitmap_covers(cur_map, emb_insideout_nest->sj_inner_tables))
-      {
-        /* Save that this range is handled with InsideOut: */
-        dups_ranges[cur_range].strategy= SJ_STRATEGY_INSIDEOUT;
-        end_of_range= TRUE;
-      }
-      else if (bitmap_covers(cur_map, emb_outer_tables | emb_sj_map))
-      {
+        SJ_TMP_TABLE::TAB sjtabs[MAX_TABLES];
+        SJ_TMP_TABLE::TAB *last_tab= sjtabs;
+        uint jt_rowid_offset= 0; // # tuple bytes are already occupied (w/o NULL bytes)
+        uint jt_null_bits= 0;    // # null bits in tuple bytes
         /*
-          This is a complete range to be handled with either DuplicateWeedout 
-          or FirstMatch
+          Walk through the range and remember
+           - tables that need their rowids to be put into temptable
+           - the last outer table
         */
-        dups_ranges[cur_range].strategy= 
-          dealing_with_jbuf? SJ_STRATEGY_DUPS_WEEDOUT_JBUF: 
-                             SJ_STRATEGY_DUPS_WEEDOUT;
-        /* 
-          This will hold tables from within the range that need to be put 
-          into the join buffer before we can use the FirstMatch on its tail.
-        */
-        dups_ranges[cur_range].outer_tables= emb_outer_tables & 
-                                             ~range_start_map;
-        end_of_range= TRUE;
-      }
-
-      if (end_of_range)
-      {
-        dups_ranges[cur_range].end_idx= i+1;
-        emb_sj_map= emb_outer_tables= 0;
-        emb_insideout_nest= NULL;
-        dealing_with_jbuf= FALSE;
-        dups_ranges[++cur_range].strategy= SJ_STRATEGY_INVALID;
-      }
-      else
-      {
-        /* We don't support interleaving for InsideOut*/
-        if (!tab->emb_sj_nest)
-          emb_insideout_nest= NULL;
-      }
-    }
-  }
-
-  THD *thd= join->thd;
-  SJ_TMP_TABLE **next_sjtbl_ptr= &join->sj_tmp_tables;
-  /*
-    The second pass: setup the chosen strategies    
-  */
-  for (int j= 0; j < cur_range; j++)
-  {
-    JOIN_TAB *tab=join->join_tab + dups_ranges[j].start_idx;
-    JOIN_TAB *jump_to;
-    bool first_match_only= FALSE;
-    if (dups_ranges[j].strategy == SJ_STRATEGY_INSIDEOUT)
-    {
-      /* We jump from the last table to the first one */
-      tab->insideout_match_tab= join->join_tab + dups_ranges[j].end_idx - 1;
-      
-      /* Calculate key length */
-      uint nparts= join->best_positions[dups_ranges[j].start_idx].insideout_parts;
-      uint keyno= join->best_positions[dups_ranges[j].start_idx].insideout_key;
-      uint keylen= 0;
-      for (uint kp=0; kp < nparts; kp++)
-        keylen += tab->table->key_info[keyno].key_part[kp].store_length;
-      tab->insideout_key_len= keylen;
-      jump_to= tab++;
-    }
-    else // DuplicateWeedout or FirstMatch
-    {
-      SJ_TMP_TABLE::TAB sjtabs[MAX_TABLES];
-      table_map cur_map= join->const_table_map | PSEUDO_TABLE_BITS;
-      uint jt_rowid_offset= 0; // # tuple bytes are already occupied (w/o NULL bytes)
-      uint jt_null_bits= 0;    // # null bits in tuple bytes
-      SJ_TMP_TABLE::TAB *last_tab= sjtabs;
-      uint rowid_keep_flags= JOIN_TAB::CALL_POSITION | JOIN_TAB::KEEP_ROWID;
-      JOIN_TAB *last_outer_tab= tab - 1;
-      first_match_only= TRUE;
-      /*
-        Walk through the range and remember
-         - tables that need their rowids to be put into temptable
-         - the last outer table
-      */
-      for (; tab < join->join_tab + dups_ranges[j].end_idx; tab++)
-      {
-        if (sj_table_is_included(join, tab))
-        {
-          last_tab->join_tab= tab;
-          last_tab->rowid_offset= jt_rowid_offset;
-          jt_rowid_offset += tab->table->file->ref_length;
-          if (tab->table->maybe_null)
+        for (JOIN_TAB *j=join->join_tab + first_table; 
+             j < join->join_tab + i + pos->n_sj_tables; j++)
+        {
+          if (sj_table_is_included(join, j))
           {
-            last_tab->null_byte= jt_null_bits / 8;
-            last_tab->null_bit= jt_null_bits++;
+            last_tab->join_tab= j;
+            last_tab->rowid_offset= jt_rowid_offset;
+            jt_rowid_offset += j->table->file->ref_length;
+            if (j->table->maybe_null)
+            {
+              last_tab->null_byte= jt_null_bits / 8;
+              last_tab->null_bit= jt_null_bits++;
+            }
+            last_tab++;
+            j->table->prepare_for_position();
+            j->keep_current_rowid= TRUE;
           }
-          last_tab++;
-          tab->table->prepare_for_position();
-          tab->rowid_keep_flags= rowid_keep_flags;
-          first_match_only= FALSE; 
-        }
-        cur_map |= tab->table->map;
-        if (!tab->emb_sj_nest && bitmap_covers(cur_map, 
-                                               dups_ranges[j].outer_tables))
-          last_outer_tab= tab;
-      }
+        }
 
-      if (jt_rowid_offset) /* Temptable has at least one rowid */
-      {
         SJ_TMP_TABLE *sjtbl;
-        uint tabs_size= (last_tab - sjtabs) * sizeof(SJ_TMP_TABLE::TAB);
-        if (!(sjtbl= (SJ_TMP_TABLE*)thd->alloc(sizeof(SJ_TMP_TABLE))) ||
-            !(sjtbl->tabs= (SJ_TMP_TABLE::TAB*) thd->alloc(tabs_size)))
-          DBUG_RETURN(TRUE);
-        memcpy(sjtbl->tabs, sjtabs, tabs_size);
-        sjtbl->tabs_end= sjtbl->tabs + (last_tab - sjtabs);
-        sjtbl->rowid_len= jt_rowid_offset;
-        sjtbl->null_bits= jt_null_bits;
-        sjtbl->null_bytes= (jt_null_bits + 7)/8;
-
-        *next_sjtbl_ptr= sjtbl;
-        next_sjtbl_ptr= &(sjtbl->next);
-        sjtbl->next= NULL;
-
-        sjtbl->tmp_table= 
-          create_duplicate_weedout_tmp_table(thd, 
-                                             sjtbl->rowid_len + 
-                                             sjtbl->null_bytes,
-                                             sjtbl);
+        if (jt_rowid_offset) /* Temptable has at least one rowid */
+        {
+          uint tabs_size= (last_tab - sjtabs) * sizeof(SJ_TMP_TABLE::TAB);
+          if (!(sjtbl= (SJ_TMP_TABLE*)thd->alloc(sizeof(SJ_TMP_TABLE))) ||
+              !(sjtbl->tabs= (SJ_TMP_TABLE::TAB*) thd->alloc(tabs_size)))
+            DBUG_RETURN(TRUE); /* purecov: inspected */
+          memcpy(sjtbl->tabs, sjtabs, tabs_size);
+          sjtbl->is_confluent= FALSE;
+          sjtbl->tabs_end= sjtbl->tabs + (last_tab - sjtabs);
+          sjtbl->rowid_len= jt_rowid_offset;
+          sjtbl->null_bits= jt_null_bits;
+          sjtbl->null_bytes= (jt_null_bits + 7)/8;
+          sjtbl->tmp_table= 
+            create_duplicate_weedout_tmp_table(thd, 
+                                               sjtbl->rowid_len + 
+                                               sjtbl->null_bytes,
+                                               sjtbl);
+          join->sj_tmp_tables.push_back(sjtbl->tmp_table);
+        }
+        else
+        {
+          /* 
+            This is confluent case where the entire subquery predicate does 
+            not depend on anything at all, ie this is 
+              WHERE const IN (uncorrelated select)
+          */
+          if (!(sjtbl= (SJ_TMP_TABLE*)thd->alloc(sizeof(SJ_TMP_TABLE))))
+            DBUG_RETURN(TRUE); /* purecov: inspected */
+          sjtbl->tmp_table= NULL;
+          sjtbl->is_confluent= TRUE;
+          sjtbl->have_confluent_row= FALSE;
+        }
+        join->join_tab[first_table].flush_weedout_table= sjtbl;
+        join->join_tab[i + pos->n_sj_tables - 1].check_weed_out_table= sjtbl;
 
-        join->join_tab[dups_ranges[j].start_idx].flush_weedout_table= sjtbl;
-        join->join_tab[dups_ranges[j].end_idx - 1].check_weed_out_table= sjtbl;
+        i += pos->n_sj_tables;
+        break;
       }
-      tab= last_outer_tab + 1;
-      jump_to= last_outer_tab;
-    }
-
-    /* Create the FirstMatch tail */
-    for (; tab < join->join_tab + dups_ranges[j].end_idx; tab++)
-    {
-      if (!tab->emb_sj_nest)
-        jump_to= tab;
-      if (first_match_only)
+      case SJ_OPT_FIRST_MATCH:
       {
-        tab->first_sj_inner_tab= join->join_tab + dups_ranges[j].start_idx;
-        tab->last_sj_inner_tab= join->join_tab + dups_ranges[j].end_idx - 1;
+        JOIN_TAB *j, *jump_to= tab-1;
+        for (j= tab; j != tab + pos->n_sj_tables; j++)
+        {
+          if (!tab->emb_sj_nest)
+            jump_to= tab;
+          else
+          {
+            tab->first_sj_inner_tab= tab;
+            tab->last_sj_inner_tab= tab + pos->n_sj_tables - 1;
+          }
+        }
+        j[-1].do_firstmatch= jump_to;
+        i += pos->n_sj_tables;
+        break;
       }
+      case SJ_OPT_NONE:
+        break;
     }
-    if (tab - 1 != jump_to)
-      tab[-1].do_firstmatch= jump_to;
   }
   DBUG_RETURN(FALSE);
 }
 
 
 /*
-  Destroy all temporary tables created by NL-semijoin runtime.
+  Destroy all temporary tables created by NL-semijoin runtime
 */
 
 static void destroy_sj_tmp_tables(JOIN *join)
 {
-  for (SJ_TMP_TABLE *sj_tbl= join->sj_tmp_tables; sj_tbl; 
-       sj_tbl= sj_tbl->next)
+  List_iterator<TABLE> it(join->sj_tmp_tables);
+  TABLE *table;
+  while ((table= it++))
   {
-    if (sj_tbl->tmp_table)
-      free_tmp_table(join->thd, sj_tbl->tmp_table);
+    /* 
+      SJ-Materialization tables are initialized for either sequential reading 
+      or index lookup, DuplicateWeedout tables are not initialized for read 
+      (we only write to them), so need to call ha_index_or_rnd_end.
+    */
+    table->file->ha_index_or_rnd_end();
+    free_tmp_table(join->thd, table);
   }
-  join->sj_tmp_tables= NULL;
+  join->sj_tmp_tables.empty();
+  join->sjm_info_list.empty();
 }
 
 
 /*
   Remove all records from all temp tables used by NL-semijoin runtime
+
+  SYNOPSIS
+    clear_sj_tmp_tables()
+      join  The join to remove tables for
+
+  DESCRIPTION
+    Remove all records from all temp tables used by NL-semijoin runtime. This 
+    must be done before every join re-execution.
 */
 
 static int clear_sj_tmp_tables(JOIN *join)
 {
   int res;
-  for (SJ_TMP_TABLE *sj_tbl= join->sj_tmp_tables; sj_tbl; 
-       sj_tbl= sj_tbl->next)
+  List_iterator<TABLE> it(join->sj_tmp_tables);
+  TABLE *table;
+  while ((table= it++))
   {
-    if (sj_tbl->tmp_table)
-    {
-      if ((res= sj_tbl->tmp_table->file->ha_delete_all_rows()))
-        return res;
-    }
+    if ((res= table->file->ha_delete_all_rows()))
+      return res; /* purecov: inspected */
+  }
+
+  SJ_MATERIALIZATION_INFO *sjm;
+  List_iterator<SJ_MATERIALIZATION_INFO> it2(join->sjm_info_list);
+  while ((sjm= it2++))
+  {
+    sjm->materialized= FALSE;
   }
   return 0;
 }
 
 
-uint make_join_orderinfo(JOIN *join);
 
 /**
   global select optimisation.
@@ -1403,6 +1422,12 @@ JOIN::optimize()
   optimized= 1;
 
   thd_proc_info(thd, "optimizing");
+  
+  /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */
+  if (flatten_subqueries())
+    DBUG_RETURN(1); /* purecov: inspected */
+  /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */
+
   row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
 	      unit->select_limit_cnt);
   /* select_limit is used to decide if we are likely to scan the whole table */
@@ -1573,6 +1598,9 @@ JOIN::optimize()
                                  QT_ORDINARY););
         conds= table_independent_conds;
       }
+      /* Create all structures needed for materialized subquery execution. */
+      if (setup_subquery_materialization())
+        DBUG_RETURN(1);
     }
   }
   if (!tables_list)
@@ -1628,15 +1656,7 @@ JOIN::optimize()
     /* Handle the case where we have an OUTER JOIN without a WHERE */
     conds=new Item_int((longlong) 1,1);	// Always true
   }
-  select= make_select(*all_tables, const_table_map,
-                      const_table_map, conds, 1, &error);
-  if (error)
-  {						/* purecov: inspected */
-    error= -1;					/* purecov: inspected */
-    DBUG_PRINT("error",("Error: make_select() failed"));
-    DBUG_RETURN(1);
-  }
-  
+  error= 0;
   reset_nj_counters(join_list);
   make_outerjoin_info(this);
 
@@ -1677,7 +1697,7 @@ JOIN::optimize()
   {
     conds=new Item_int((longlong) 0,1);	// Always false
   }
-  if (make_join_select(this, select, conds))
+  if (make_join_select(this, conds))
   {
     zero_result_cause=
       "Impossible WHERE noticed after reading const tables";
@@ -1894,11 +1914,6 @@ JOIN::optimize()
     (select_options & (SELECT_DESCRIBE | SELECT_NO_JOIN_CACHE)) |
     (select_lex->ftfunc_list->elements ?  SELECT_NO_JOIN_CACHE : 0);
 
-  sj_tmp_tables= NULL;
-  if (!select_lex->sj_nests.is_empty())
-    setup_semijoin_dups_elimination(this, select_opts_for_readinfo,
-                                    no_jbuf_after);
-
   // No cache for MATCH == 'Don't use join buffering when we use MATCH'.
   if (make_join_readinfo(this, select_opts_for_readinfo, no_jbuf_after))
     DBUG_RETURN(1);
@@ -2905,7 +2920,6 @@ JOIN::destroy()
   if (exec_tmp_table2)
     free_tmp_table(thd, exec_tmp_table2);
   destroy_sj_tmp_tables(this);
-  delete select;
   delete_dynamic(&keyuse);
   delete procedure;
   DBUG_RETURN(error);
@@ -3005,7 +3019,7 @@ mysql_select(THD *thd, Item ***rref_poin
   else
   {
     if (!(join= new JOIN(thd, fields, select_options, result)))
-	DBUG_RETURN(TRUE);
+	DBUG_RETURN(TRUE); /* purecov: inspected */
     thd_proc_info(thd, "init");
     thd->used_tables=0;                         // Updated by setup_fields
     if (err= join->prepare(rref_pointer_array, tables, wild_num,
@@ -3016,14 +3030,6 @@ mysql_select(THD *thd, Item ***rref_poin
     }
   }
 
-  /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */
-  if (join->flatten_subqueries())
-  {
-    err= 1;
-    goto err;
-  }
-  /* dump_TABLE_LIST_struct(select_lex, select_lex->leaf_tables); */
-
   if ((err= join->optimize()))
   {
     goto err;					// 1
@@ -3252,6 +3258,7 @@ bool convert_subq_to_sj(JOIN *parent_joi
   sj_nest->join_list= emb_join_list;
   sj_nest->embedding= emb_tbl_nest;
   sj_nest->alias= (char*) "(sj-nest)";
+  sj_nest->sj_subq_pred= subq_pred;
   /* Nests do not participate in those 'chains', so: */
   /* sj_nest->next_leaf= sj_nest->next_local= sj_nest->next_global == NULL*/
   emb_join_list->push_back(sj_nest);
@@ -3335,7 +3342,7 @@ bool convert_subq_to_sj(JOIN *parent_joi
 
   /*
     Create the IN-equalities and inject them into semi-join's ON expression.
-    Additionally, for InsideOut strategy
+    Additionally, for LooseScan strategy
      - Record the number of IN-equalities.
      - Create list of pointers to (oe1, ..., ieN). We'll need the list to
        see which of the expressions are bound and which are not (for those
@@ -3355,9 +3362,9 @@ bool convert_subq_to_sj(JOIN *parent_joi
   {
     nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr);
 
-    Item *item_eq= new Item_func_eq(subq_pred->left_expr, 
+    Item_func_eq *item_eq= new Item_func_eq(subq_pred->left_expr, 
                                     subq_lex->ref_pointer_array[0]);
-    item_eq->name= (char*)subq_sj_cond_name;
+    item_eq->in_equality_no= 0;
     sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq);
   }
   else
@@ -3366,10 +3373,10 @@ bool convert_subq_to_sj(JOIN *parent_joi
     {
       nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr->
                                                 element_index(i));
-      Item *item_eq= 
+      Item_func_eq *item_eq= 
         new Item_func_eq(subq_pred->left_expr->element_index(i), 
                          subq_lex->ref_pointer_array[i]);
-      item_eq->name= (char*)subq_sj_cond_name + (i % 64);
+      item_eq->in_equality_no= i;
       sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq);
     }
   }
@@ -3418,13 +3425,46 @@ bool convert_subq_to_sj(JOIN *parent_joi
 
 
 /*
-  Convert candidate subquery predicates to semi-joins
+  Convert semi-join subquery predicates into semi-join join nests
 
   SYNOPSIS
     JOIN::flatten_subqueries()
  
   DESCRIPTION
-    Convert candidate subquery predicates to semi-joins.
+
+    Convert candidate subquery predicates into semi-join join nests. This 
+    transformation is performed once in query lifetime and is irreversible.
+    
+    Conversion of one subquery predicate
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    We start with a join that has a semi-join subquery:
+
+      SELECT ...
+      FROM ot, ...
+      WHERE oe IN (SELECT ie FROM it1 ... itN WHERE subq_where) AND outer_where
+
+    and convert it into a semi-join nest:
+
+      SELECT ...
+      FROM ot SEMI JOIN (it1 ... itN), ...
+      WHERE outer_where AND subq_where AND oe=ie
+
+    that is, in order to do the conversion, we need to 
+
+     * Create the "SEMI JOIN (it1 .. itN)" part and add it into the parent
+       query's FROM structure.
+     * Add "AND subq_where AND oe=ie" into parent query's WHERE (or ON if
+       the subquery predicate was in an ON expression)
+     * Remove the subquery predicate from the parent query's WHERE
+
+    Considerations when converting many predicates
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    A join may have at most MAX_TABLES tables. This may prevent us from
+    flattening all subqueries when the total number of tables in parent and
+    child selects exceeds MAX_TABLES.
+    We deal with this problem by flattening children's subqueries first and
+    then using a heuristic rule to determine each subquery predicate's
+    "priority".
 
   RETURN 
     FALSE  OK
@@ -3441,7 +3481,7 @@ bool JOIN::flatten_subqueries()
   if (sj_subselects.elements() == 0)
     DBUG_RETURN(FALSE);
 
-  /* 1. Fix children subqueries */
+  /* First, convert child join's subqueries. We proceed bottom-up here */
   for (in_subq= sj_subselects.front(), in_subq_end= sj_subselects.back(); 
        in_subq != in_subq_end; in_subq++)
   {
@@ -3452,6 +3492,20 @@ bool JOIN::flatten_subqueries()
     (*in_subq)->sj_convert_priority= 
       (*in_subq)->is_correlated * MAX_TABLES + child_join->outer_tables;
   }
+  
+  // Temporary measure: disable semi-joins when they are together with outer
+  // joins.
+  for (TABLE_LIST *tbl= select_lex->leaf_tables; tbl; tbl=tbl->next_leaf)
+  {
+    TABLE_LIST *embedding= tbl->embedding;
+    if (tbl->on_expr || (tbl->embedding && !(embedding->sj_on_expr && 
+                                            !embedding->embedding)))
+    {
+      in_subq= sj_subselects.front();
+      arena= thd->activate_stmt_arena_if_needed(&backup);
+      goto skip_conversion;
+    }
+  }
 
   //dump_TABLE_LIST_struct(select_lex, select_lex->leaf_tables);
   /* 
@@ -3469,9 +3523,11 @@ bool JOIN::flatten_subqueries()
        tables + (*in_subq)->unit->first_select()->join->tables < MAX_TABLES;
        in_subq++)
   {
-    if (replace_where_subcondition(this, (*in_subq)->emb_on_expr_nest,
-                                   *in_subq, new Item_int(1), FALSE))
-      DBUG_RETURN(TRUE);
+    Item **tree= ((*in_subq)->emb_on_expr_nest == (TABLE_LIST*)1)?
+                   &conds : &((*in_subq)->emb_on_expr_nest->on_expr);
+    if (replace_where_subcondition(this, tree, *in_subq, new Item_int(1),
+                                   FALSE))
+      DBUG_RETURN(TRUE); /* purecov: inspected */
   }
  
   for (in_subq= sj_subselects.front(); 
@@ -3482,9 +3538,7 @@ bool JOIN::flatten_subqueries()
     if (convert_subq_to_sj(this, *in_subq))
       DBUG_RETURN(TRUE);
   }
-  if (arena)
-    thd->restore_active_arena(arena, &backup);
-
+skip_conversion:
   /* 3. Finalize those we didn't convert */
   for (; in_subq!= in_subq_end; in_subq++)
   {
@@ -3508,10 +3562,26 @@ bool JOIN::flatten_subqueries()
 
     Item *substitute= (*in_subq)->substitution;
     bool do_fix_fields= !(*in_subq)->substitution->fixed;
-    if (replace_where_subcondition(this, (*in_subq)->emb_on_expr_nest, 
-                                   *in_subq, substitute, do_fix_fields))
+    Item **tree= ((*in_subq)->emb_on_expr_nest == (TABLE_LIST*)1)?
+                   &conds : &((*in_subq)->emb_on_expr_nest->on_expr);
+    if (replace_where_subcondition(this, tree, *in_subq, substitute, 
+                                   do_fix_fields))
       DBUG_RETURN(TRUE);
+    (*in_subq)->substitution= NULL;
+     
+    if (!thd->stmt_arena->is_conventional())
+    {
+      tree= ((*in_subq)->emb_on_expr_nest == (TABLE_LIST*)1)?
+                     &select_lex->prep_where : &((*in_subq)->emb_on_expr_nest->prep_on_expr);
+
+      if (replace_where_subcondition(this, tree, *in_subq, substitute, 
+                                     FALSE))
+        DBUG_RETURN(TRUE);
+    }
   }
+
+  if (arena)
+    thd->restore_active_arena(arena, &backup);
   sj_subselects.clear();
   DBUG_RETURN(FALSE);
 }
@@ -3657,6 +3727,19 @@ bool find_eq_ref_candidate(TABLE *table,
 
     This operation is (and should be) performed at each PS execution since
     tables may become/cease to be constant across PS reexecutions.
+    
+  NOTE
+    Table pullout may make uncorrelated subquery correlated. Consider this
+    example:
+    
+     ... WHERE oe IN (SELECT it1.primary_key WHERE p(it1, it2) ... ) 
+    
+    here table it1 can be pulled out (we have it1.primary_key=oe which gives
+    us functional dependency). Once it1 is pulled out, all references to it1
+    from p(it1, it2) become references to outside of the subquery and thus
+    make the subquery (i.e. its semi-join nest) correlated.
+    Making the subquery (i.e. its semi-join nest) correlated prevents us from
+    using Materialization or LooseScan to execute it. 
 
   RETURN 
     0 - OK
@@ -3713,6 +3796,11 @@ int pull_out_semijoin_tables(JOIN *join)
             pulled_tables |= tbl->table->map;
             DBUG_PRINT("info", ("Table %s pulled out (reason: func dep)",
                                 tbl->table->alias));
+            /*
+              Pulling a table out of uncorrelated subquery in general makes
+              makes it correlated. See the NOTE to this funtion. 
+            */
+            sj_nest->sj_subq_pred->is_correlated= TRUE;
           }
         }
       }
@@ -3739,14 +3827,12 @@ int pull_out_semijoin_tables(JOIN *join)
         {
           if (inner_tables & tbl->table->map)
           {
-            // This table is not pulled out
+            /* This table is not pulled out */
             tbl->table->reginfo.join_tab->emb_sj_nest= sj_nest;
           }
           else
           {
-            /* 
-              This table has been pulled out of the semi-join nest
-            */
+            /* This table has been pulled out of the semi-join nest */
             tbl->table->reginfo.join_tab->emb_sj_nest= NULL;
             /*
               Pull the table up in the same way as simplify_joins() does:
@@ -3777,6 +3863,7 @@ int pull_out_semijoin_tables(JOIN *join)
   DBUG_RETURN(0);
 }
 
+
 /*****************************************************************************
   Create JOIN_TABS, make a guess about the table types,
   Approximate how many records will be used in each table
@@ -3822,6 +3909,65 @@ typedef struct st_sargable_param
   uint num_values;           /* number of values in the above array      */
 } SARGABLE_PARAM;  
 
+
+
+/*
+  Get estimated record length for semi-join materialization temptable
+  
+  SYNOPSIS
+    get_tmp_table_rec_length()
+      items  IN subquery's select list.
+
+  DESCRIPTION
+    Calculate estimated record length for semi-join materialization
+    temptable. It's an estimate because we don't follow every bit of
+    create_tmp_table()'s logic. This isn't necessary as the return value of
+    this function is used only for cost calculations.
+
+  RETURN
+    Length of the temptable record, in bytes
+*/
+
+static uint get_tmp_table_rec_length(List<Item> &items)
+{
+  uint len= 0;
+  Item *item;
+  List_iterator<Item> it(items);
+  while ((item= it++))
+  {
+    switch (item->result_type()) {
+    case REAL_RESULT:
+      len += sizeof(double);
+      break;
+    case INT_RESULT:
+      if (item->max_length >= (MY_INT32_NUM_DECIMAL_DIGITS - 1))
+        len += 8;
+      else
+        len += 4;
+      break;
+    case STRING_RESULT:
+      enum enum_field_types type;
+      /* DATE/TIME and GEOMETRY fields have STRING_RESULT result type.  */
+      if ((type= item->field_type()) == MYSQL_TYPE_DATETIME ||
+          type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE ||
+          type == MYSQL_TYPE_TIMESTAMP || type == MYSQL_TYPE_GEOMETRY)
+        len += 8;
+      else
+        len += item->max_length;
+      break;
+    case DECIMAL_RESULT:
+      len += 10;
+      break;
+    case ROW_RESULT:
+    default:
+      DBUG_ASSERT(0); /* purecov: deadcode */
+      break;
+    }
+  }
+  return len;
+}
+
+
 /**
   Calculate the best possible join and initialize the join structure.
 
@@ -4260,10 +4406,15 @@ make_join_statistics(JOIN *join, TABLE_L
   join->const_tables=const_count;
   join->found_const_table_map=found_const_table_map;
 
-  /* Find an optimal join order of the non-constant tables. */
   if (join->const_tables != join->tables)
-  {
     optimize_keyuse(join, keyuse_array);
+   
+  if (optimize_semijoin_nests(join, all_table_map))
+    DBUG_RETURN(TRUE); /* purecov: inspected */
+
+  /* Find an optimal join order of the non-constant tables. */
+  if (join->const_tables != join->tables)
+  {
     if (choose_plan(join, all_table_map & ~join->const_table_map))
       DBUG_RETURN(TRUE);
   }
@@ -4278,6 +4429,140 @@ make_join_statistics(JOIN *join, TABLE_L
 }
 
 
+/* 
+  Optimize semi-join nests that could be run with sj-materialization
+
+  SYNOPSIS
+    optimize_semijoin_nests()
+      join           The join to optimize semi-join nests for
+      all_table_map  Bitmap of all tables in the join
+
+  DESCRIPTION
+    Optimize each of the semi-join nests that can be run with
+    materialization. For each of the nests, we
+     - Generate the best join order for this "sub-join" and remember it;
+     - Remember the sub-join execution cost (it's part of materialization
+       cost);
+     - Calculate other costs that will be incurred if we decide 
+       to use materialization strategy for this semi-join nest.
+
+    All obtained information is saved and will be used by the main join
+    optimization pass.
+
+  RETURN
+    FALSE  Ok 
+    TRUE   Out of memory error
+*/
+
+static bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
+{
+  DBUG_ENTER("optimize_semijoin_nests");
+  List_iterator<TABLE_LIST> sj_list_it(join->select_lex->sj_nests);
+  TABLE_LIST *sj_nest;
+  if (!optimizer_flag(join->thd, OPTIMIZER_SWITCH_NO_MATERIALIZATION))
+  {
+    while ((sj_nest= sj_list_it++))
+    {
+      sj_nest->sj_mat_info= NULL;
+      if (sj_nest->sj_inner_tables && /* not everything was pulled out */
+          !sj_nest->sj_subq_pred->is_correlated && 
+           sj_nest->sj_subq_pred->types_allow_materialization)
+      {
+        join->emb_sjm_nest= sj_nest;
+        if (choose_plan(join, all_table_map))
+          DBUG_RETURN(TRUE); /* purecov: inspected */
+        /*
+          The best plan to run the subquery is now in join->best_positions,
+          save it.
+        */
+        uint n_tables= my_count_bits(sj_nest->sj_inner_tables);
+        SJ_MATERIALIZATION_INFO* sjm;
+        if (!(sjm= new SJ_MATERIALIZATION_INFO) ||
+            !(sjm->positions= (POSITION*)join->thd->alloc(sizeof(POSITION)*
+                                                          n_tables)))
+          DBUG_RETURN(TRUE); /* purecov: inspected */
+        sjm->tables= n_tables;
+        sjm->is_used= FALSE;
+        double subjoin_out_rows, subjoin_read_time;
+        get_partial_join_cost(join, n_tables,
+                              &subjoin_read_time, &subjoin_out_rows);
+
+        sjm->materialization_cost.convert_from_cost(subjoin_read_time);
+        sjm->rows= subjoin_out_rows;
+
+        List<Item> &right_expr_list= 
+          sj_nest->sj_subq_pred->unit->first_select()->item_list;
+        /*
+          Adjust output cardinality estimates. If the subquery has form
+
+           ... oe IN (SELECT t1.colX, t2.colY, func(X,Y,Z) )
+
+           then the number of distinct output record combinations has an
+           upper bound of product of number of records matching the tables 
+           that are used by the SELECT clause.
+           TODO:
+             We can get a more precise estimate if we
+              - use rec_per_key cardinality estimates. For simple cases like 
+                "oe IN (SELECT t.key ...)" it is trivial. 
+              - Functional dependencies between the tables in the semi-join
+                nest (the payoff is probably less here?)
+        */
+        {
+          for (uint i=0 ; i < join->const_tables + sjm->tables ; i++)
+          {
+            JOIN_TAB *tab= join->best_positions[i].table;
+            join->map2table[tab->table->tablenr]= tab;
+          }
+          List_iterator<Item> it(right_expr_list);
+          Item *item;
+          table_map map= 0;
+          while ((item= it++))
+            map |= item->used_tables();
+          map= map & ~PSEUDO_TABLE_BITS;
+          Table_map_iterator tm_it(map);
+          int tableno;
+          double rows= 1.0;
+          while ((tableno = tm_it.next_bit()) != Table_map_iterator::BITMAP_END)
+            rows *= join->map2table[tableno]->table->quick_condition_rows;
+          sjm->rows= min(sjm->rows, rows);
+        }
+        memcpy(sjm->positions, join->best_positions + join->const_tables, 
+               sizeof(POSITION) * n_tables);
+
+        /*
+          Calculate temporary table parameters and usage costs
+        */
+        uint rowlen= get_tmp_table_rec_length(right_expr_list);
+        double lookup_cost;
+        if (rowlen * subjoin_out_rows< join->thd->variables.max_heap_table_size)
+          lookup_cost= HEAP_TEMPTABLE_LOOKUP_COST;
+        else
+          lookup_cost= DISK_TEMPTABLE_LOOKUP_COST;
+
+        /*
+          Let materialization cost include the cost to write the data into the
+          temporary table:
+        */ 
+        sjm->materialization_cost.add_io(subjoin_out_rows, lookup_cost);
+        
+        /*
+          Set the cost to do a full scan of the temptable (will need this to 
+          consider doing sjm-scan):
+        */ 
+        sjm->scan_cost.zero();
+        sjm->scan_cost.add_io(sjm->rows, lookup_cost);
+
+        sjm->lookup_cost.convert_from_cost(lookup_cost);
+        sj_nest->sj_mat_info= sjm;
+        DBUG_EXECUTE("opt", print_sjm(sjm););
+      }
+    }
+  }
+  join->emb_sjm_nest= NULL;
+  DBUG_RETURN(FALSE);
+}
+
+
 /*****************************************************************************
   Check with keys are used and with tables references with tables
   Updates in stat:
@@ -4433,6 +4718,50 @@ merge_key_fields(KEY_FIELD *start,KEY_FI
   return first_free;
 }
 
+/*
+  Given a field, return its index in semi-join's select list, or UINT_MAX
+
+  DESCRIPTION
+    Given a field, we find its table; then see if the table is within a
+    semi-join nest and if the field was in select list of the subselect.
+    If it was, we return field's index in the select list. The value is used
+    by LooseScan strategy.
+*/
+
+static uint get_semi_join_select_list_index(Field *field)
+{
+  uint res= UINT_MAX;
+  TABLE_LIST *emb_sj_nest;
+  if ((emb_sj_nest= field->table->pos_in_table_list->embedding) &&
+      emb_sj_nest->sj_on_expr)
+  {
+    Item_in_subselect *subq_pred= emb_sj_nest->sj_subq_pred;
+    st_select_lex *subq_lex= subq_pred->unit->first_select();
+    if (subq_pred->left_expr->cols() == 1)
+    {
+      Item *sel_item= subq_lex->ref_pointer_array[0];
+      if (sel_item->type() == Item::FIELD_ITEM &&
+          ((Item_field*)sel_item)->field->eq(field))
+      {
+        res= 0;
+      }
+    }
+    else
+    {
+      for (uint i= 0; i < subq_pred->left_expr->cols(); i++)
+      {
+        Item *sel_item= subq_lex->ref_pointer_array[i];
+        if (sel_item->type() == Item::FIELD_ITEM &&
+            ((Item_field*)sel_item)->field->eq(field))
+        {
+          res= i;
+          break;
+        }
+      }
+    }
+  }
+  return res;
+}
 
 /**
   Add a possible key to array of possible keys if it's usable as a key
@@ -4598,9 +4927,8 @@ add_key_field(KEY_FIELD **key_fields,uin
                                   ((*value)->type() == Item::FIELD_ITEM) &&
                                   ((Item_field*)*value)->field->maybe_null());
   (*key_fields)->cond_guard= NULL;
-  (*key_fields)->sj_pred_no= (cond->name >= subq_sj_cond_name && 
-                              cond->name < subq_sj_cond_name + 64)? 
-                              cond->name - subq_sj_cond_name: UINT_MAX;
+  
+  (*key_fields)->sj_pred_no= get_semi_join_select_list_index(field);
   (*key_fields)++;
 }
 
@@ -4901,7 +5229,8 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array
           keyuse.null_rejecting= key_field->null_rejecting;
           keyuse.cond_guard= key_field->cond_guard;
           keyuse.sj_pred_no= key_field->sj_pred_no;
-          keyuse.ref_table_rows= 0;
+          /* This will be set accordingly in optimize_keyuse */
+          keyuse.ref_table_rows= ~(ha_rows) 0;
 	  (void) insert_dynamic(keyuse_array,(uchar*) &keyuse);
 	}
       }
@@ -5361,6 +5690,10 @@ set_position(JOIN *join,uint idx,JOIN_TA
   join->positions[idx].records_read=1.0;	/* This is a const table */
   join->positions[idx].ref_depend_map= 0;
 
+  join->positions[idx].loosescan_key= MAX_KEY; /* Not a LooseScan */
+  join->positions[idx].sj_strategy= SJ_OPT_NONE;
+  join->positions[idx].use_join_buffer= FALSE;
+
   /* Move the const table as down as possible in best_ref */
   JOIN_TAB **pos=join->best_ref+idx+1;
   JOIN_TAB *next=join->best_ref[idx];
@@ -5415,6 +5748,267 @@ ulonglong get_bound_sj_equalities(TABLE_
 }
 
 
+/*
+  This is a class for considering possible loose index scan optimizations.
+  It's usage pattern is as follows:
+    best_access_path()
+    {
+       Loose_scan_opt opt;
+
+       opt.init()
+       for each index we can do ref access with
+       {
+         opt.next_ref_key();
+         for each keyuse 
+           opt.add_keyuse();
+         opt.check_ref_access();
+       }
+
+       if (some criteria for range scans)
+         opt.check_range_access();
+       
+       opt.get_best_option();
+    }
+*/
+
+class Loose_scan_opt
+{
+public:
+  /* All methods must check this before doing anything else */
+  bool try_loosescan;
+
+  /*
+    If we consider (oe1, .. oeN) IN (SELECT ie1, .. ieN) then ieK=oeK is
+    called sj-equality. If oeK depends only on preceding tables then such
+    equality is called 'bound'.
+  */
+  ulonglong bound_sj_equalities;
+ 
+  /* Accumulated properties of ref access we're now considering: */
+  ulonglong handled_sj_equalities;
+  key_part_map loose_scan_keyparts;
+  uint max_loose_keypart;
+  bool part1_conds_met;
+
+  /*
+    Use of quick select is a special case. Some of its properties:
+  */
+  uint quick_uses_applicable_index;
+  uint quick_max_loose_keypart;
+  
+  /* Best loose scan method so far */
+  uint   best_loose_scan_key;
+  double best_loose_scan_cost;
+  double best_loose_scan_records;
+  KEYUSE *best_loose_scan_start_key;
+
+  uint best_max_loose_keypart;
+
+  Loose_scan_opt():
+    try_loosescan(FALSE),
+    bound_sj_equalities(0),
+    quick_uses_applicable_index(FALSE)
+  {
+    LINT_INIT(quick_max_loose_keypart); /* Protected by quick_uses_applicable_index */
+    /* The following are protected by best_loose_scan_cost!= DBL_MAX */
+    LINT_INIT(best_loose_scan_key);
+    LINT_INIT(best_loose_scan_records);
+    LINT_INIT(best_max_loose_keypart);
+    LINT_INIT(best_loose_scan_start_key);
+  }
+  
+  void init(JOIN *join, JOIN_TAB *s, table_map remaining_tables)
+  {
+    /*
+      Discover the bound equalities. We need to do this if
+        1. The next table is an SJ-inner table, and
+        2. It is the first table from that semijoin, and
+        3. We're not within a semi-join range (i.e. all semi-joins either have
+           all or none of their tables in join_table_map), except
+           s->emb_sj_nest (which we've just entered, see #2).
+        4. All non-IN-equality correlation references from this sj-nest are 
+           bound
+        5. But some of the IN-equalities aren't (so this can't be handled by 
+           FirstMatch strategy)
+    */
+    best_loose_scan_cost= DBL_MAX;
+    if (!join->emb_sjm_nest && s->emb_sj_nest &&                        // (1)
+        s->emb_sj_nest->sj_in_exprs < 64 && 
+        ((remaining_tables & s->emb_sj_nest->sj_inner_tables) ==        // (2)
+         s->emb_sj_nest->sj_inner_tables) &&                            // (2)
+        join->cur_sj_inner_tables == 0 &&                                  // (3)
+        !(remaining_tables & 
+          s->emb_sj_nest->nested_join->sj_corr_tables) &&               // (4)
+        remaining_tables & s->emb_sj_nest->nested_join->sj_depends_on &&// (5)
+        !optimizer_flag(join->thd, OPTIMIZER_SWITCH_NO_LOOSE_SCAN))
+    {
+      /* This table is an LooseScan scan candidate */
+      bound_sj_equalities= get_bound_sj_equalities(s->emb_sj_nest, 
+                                                   remaining_tables);
+      try_loosescan= TRUE;
+      DBUG_PRINT("info", ("Will try LooseScan scan, bound_map=%llx",
+                          (longlong)bound_sj_equalities));
+    }
+  }
+
+  void next_ref_key()
+  {
+    handled_sj_equalities=0;
+    loose_scan_keyparts= 0;
+    max_loose_keypart= 0;
+    part1_conds_met= FALSE;
+  }
+  
+  void add_keyuse(table_map remaining_tables, KEYUSE *keyuse)
+  {
+    if (try_loosescan && keyuse->sj_pred_no != UINT_MAX)
+    {
+      if (!(remaining_tables & keyuse->used_tables))
+      {
+        /* 
+          This allows to use equality propagation to infer that some 
+          sj-equalities are bound.
+        */
+        bound_sj_equalities |= 1ULL << keyuse->sj_pred_no;
+      }
+      else
+      {
+        handled_sj_equalities |= 1ULL << keyuse->sj_pred_no;
+        loose_scan_keyparts |= ((key_part_map)1) << keyuse->keypart;
+        set_if_bigger(max_loose_keypart, keyuse->keypart);
+      }
+    }
+  }
+
+  bool have_a_case() { return test(handled_sj_equalities); }
+
+  void check_ref_access_part1(JOIN_TAB *s, uint key, KEYUSE *start_key, 
+                              table_map found_part)
+  {
+    /*
+      Check if we can use LooseScan semi-join strategy. We can if
+      1. This is the right table at right location
+      2. All IN-equalities are either
+         - "bound", ie. the outer_expr part refers to the preceding tables
+         - "handled", ie. covered by the index we're considering
+      3. Index order allows to enumerate subquery's duplicate groups in
+         order. This happens when the index definition matches this
+         pattern:
+
+           (handled_col|bound_col)* (other_col|bound_col)
+
+    */
+    if (try_loosescan &&                                       // (1)
+        (handled_sj_equalities | bound_sj_equalities) ==         // (2)
+        PREV_BITS(ulonglong, s->emb_sj_nest->sj_in_exprs) &&     // (2)
+        (PREV_BITS(key_part_map, max_loose_keypart+1) &        // (3)
+         (found_part | loose_scan_keyparts)) ==                // (3)
+         (found_part | loose_scan_keyparts) &&                 // (3)
+        !key_uses_partial_cols(s->table, key))
+    {
+      /* Ok, can use the strategy */
+      part1_conds_met= TRUE;
+      if (s->quick && s->quick->index == key && 
+          s->quick->get_type() == QUICK_SELECT_I::QS_TYPE_RANGE)
+      {
+        quick_uses_applicable_index= TRUE;
+        quick_max_loose_keypart= max_loose_keypart;
+      }
+      DBUG_PRINT("info", ("Can use LooseScan scan"));
+
+      /* 
+        Check if this is a confluent where there are no usable bound
+        IN-equalities, e.g. we have
+
+          outer_expr IN (SELECT innertbl.key FROM ...) 
+        
+        and outer_expr cannot be evaluated yet, so it's actually full
+        index scan and not a ref access
+      */
+      if (!(found_part & 1 ) && /* no usable ref access for 1st key part */
+          s->table->covering_keys.is_set(key))
+      {
+        DBUG_PRINT("info", ("Can use full index scan for LooseScan"));
+        
+        /* Calculate the cost of complete loose index scan.  */
+        double records= rows2double(s->table->file->stats.records);
+
+        /* The cost is entire index scan cost (divided by 2) */
+        double read_time= s->table->file->index_only_read_time(key, records);
+
+        /*
+          Now find out how many different keys we will get (for now we
+          ignore the fact that we have "keypart_i=const" restriction for
+          some key components, that may make us think think that loose
+          scan will produce more distinct records than it actually will)
+        */
+        ulong rpc;
+        if ((rpc= s->table->key_info[key].rec_per_key[max_loose_keypart]))
+          records= records / rpc;
+
+        // TODO: previous version also did /2
+        if (read_time < best_loose_scan_cost)
+        {
+          best_loose_scan_key= key;
+          best_loose_scan_cost= read_time;
+          best_loose_scan_records= records;
+          best_max_loose_keypart= max_loose_keypart;
+          best_loose_scan_start_key= start_key;
+        }
+      }
+    }
+  }
+  
+  void check_ref_access_part2(uint key, KEYUSE *start_key, double records, 
+                              double read_time)
+  {
+    if (part1_conds_met && read_time < best_loose_scan_cost)
+    {
+      /* TODO use rec-per-key-based fanout calculations */
+      best_loose_scan_key= key;
+      best_loose_scan_cost= read_time;
+      best_loose_scan_records= records;
+      best_max_loose_keypart= max_loose_keypart;
+      best_loose_scan_start_key= start_key;
+    }
+  }
+
+  void check_range_access(JOIN *join, uint idx, QUICK_SELECT_I *quick)
+  {
+    /* TODO: this the right part restriction: */
+    if (quick_uses_applicable_index && idx == join->const_tables && 
+        quick->read_time < best_loose_scan_cost)
+    {
+      best_loose_scan_key= quick->index;
+      best_loose_scan_cost= quick->read_time;
+      /* this is ok because idx == join->const_tables */
+      best_loose_scan_records= rows2double(quick->records);
+      best_max_loose_keypart= quick_max_loose_keypart;
+      best_loose_scan_start_key= NULL;
+    }
+  }
+
+  void save_to_position(JOIN_TAB *tab, POSITION *pos)
+  {
+    pos->read_time=       best_loose_scan_cost;
+    if (best_loose_scan_cost != DBL_MAX)
+    {
+      pos->records_read=    best_loose_scan_records;
+      pos->key=             best_loose_scan_start_key;
+      pos->loosescan_key=   best_loose_scan_key;
+      pos->loosescan_parts= best_max_loose_keypart + 1;
+      pos->use_join_buffer= FALSE;
+      pos->table=           tab;
+      // todo need ref_depend_map ?
+      DBUG_PRINT("info", ("Produced a LooseScan plan, key %s, %s",
+                          tab->table->key_info[best_loose_scan_key].name,
+                          best_loose_scan_start_key? "(ref access)":
+                                                     "(range/index access)"));
+    }
+  }
+};
+
+
 /**
   Find the best access path for an extension of a partial execution
   plan and add this path to the plan.
@@ -5432,9 +6026,12 @@ ulonglong get_bound_sj_equalities(TABLE_
   @param thd              thread for the connection that submitted the query
   @param remaining_tables set of tables not included into the partial plan yet
   @param idx              the length of the partial plan
+  @param disable_jbuf     TRUE<=> Don't use join buffering
   @param record_count     estimate for the number of records returned by the
                           partial plan
-  @param read_time        the cost of the partial plan
+  @param pos              OUT Table access plan
+  @param loose_scan_pos   OUT Table plan that uses loosescan, or set cost to 
+                              DBL_MAX if not possible.
 
   @return
     None
@@ -5443,12 +6040,14 @@ ulonglong get_bound_sj_equalities(TABLE_
 static void
 best_access_path(JOIN      *join,
                  JOIN_TAB  *s,
-                 THD       *thd,
                  table_map remaining_tables,
                  uint      idx,
+                 bool      disable_jbuf,
                  double    record_count,
-                 double    read_time)
+                 POSITION *pos,
+                 POSITION *loose_scan_pos)
 {
+  THD *thd= join->thd;
   KEYUSE *best_key=         0;
   uint best_max_key_part=   0;
   my_bool found_constraint= 0;
@@ -5458,52 +6057,19 @@ best_access_path(JOIN      *join,
   table_map best_ref_depends_map= 0;
   double tmp;
   ha_rows rec;
-  uint best_is_sj_inside_out= MAX_KEY;
-  uint best_sj_keyparts;
-  bool try_sj_inside_out= FALSE;
-  uint sj_insideout_quick_select= FALSE;
-  uint sj_insideout_quick_max_sj_keypart;
-  uint sj_inside_out_scan= MAX_KEY;
+  bool best_uses_jbuf= FALSE;
+
+  Loose_scan_opt loose_scan_opt;
   DBUG_ENTER("best_access_path");
   
-  LINT_INIT(best_sj_keyparts); // Protected by sj_inside_out_scan
-  LINT_INIT(sj_insideout_quick_max_sj_keypart); // Protected by sj_insideout_quick_*
+  loose_scan_opt.init(join, s, remaining_tables);
+  
   if (s->keyuse)
   {                                            /* Use key if possible */
     TABLE *table= s->table;
     KEYUSE *keyuse,*start_key=0;
     double best_records= DBL_MAX;
     uint max_key_part=0;
-    ulonglong bound_sj_equalities= 0;
-    /*
-      Discover the bound equalites. We need to do this, if
-        1. The next table is an SJ-inner table, and
-        2. It is the first table from that semijoin, and
-        3. We're not within a semi-join range (i.e. all semi-joins either have
-           all or none of their tables in join_table_map), except
-           s->emb_sj_nest (which we've just entered, see #2).
-        4. All non-IN-equality correlation references from this sj-nest are 
-           bound
-        5. But some of the IN-equalities aren't (so this can't be handled by 
-           FirstMatch strategy)
-    */
-    if (s->emb_sj_nest &&                                               // (1)
-        s->emb_sj_nest->sj_in_exprs < 64 && 
-        ((remaining_tables & s->emb_sj_nest->sj_inner_tables) ==        // (2)
-         s->emb_sj_nest->sj_inner_tables) &&                            // (2)
-        join->cur_emb_sj_nests == s->emb_sj_nest->sj_inner_tables &&    // (3)
-        !(remaining_tables & 
-          s->emb_sj_nest->nested_join->sj_corr_tables) &&               // (4)
-        remaining_tables & s->emb_sj_nest->nested_join->sj_depends_on &&// (5)
-        !test(thd->variables.optimizer_switch & OPTIMIZER_SWITCH_NO_LOOSE_SCAN))
-    {
-      /* This table is an InsideOut scan candidate */
-      bound_sj_equalities= get_bound_sj_equalities(s->emb_sj_nest, 
-                                                   remaining_tables);
-      try_sj_inside_out= TRUE;
-      DBUG_PRINT("info", ("Will try InsideOut scan, bound_map=%llx",
-                          (longlong)bound_sj_equalities));
-    }
 
     /* Test how we can use keys */
     rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE;  // Assumed records/key
@@ -5521,9 +6087,8 @@ best_access_path(JOIN      *join,
 
       /* Calculate how many key segments of the current key we can use */
       start_key= keyuse;
-      ulonglong handled_sj_equalities=0;
-      key_part_map sj_insideout_map= 0;
-      uint max_sj_keypart= 0;
+
+      loose_scan_opt.next_ref_key();
       DBUG_PRINT("info", ("Considering ref access on key %s",
                           keyuse->table->key_info[keyuse->key].name));
 
@@ -5535,7 +6100,6 @@ best_access_path(JOIN      *join,
         
         do /* For each way to access the keypart */
         {
-
           /*
             if 1. expression doesn't refer to forward tables
                2. we won't get two ref-or-null's
@@ -5564,19 +6128,7 @@ best_access_path(JOIN      *join,
             if (keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL)
               ref_or_null_part |= keyuse->keypart_map;
           }
-
-          if (try_sj_inside_out && keyuse->sj_pred_no != UINT_MAX)
-          {
-            if (!(remaining_tables & keyuse->used_tables))
-              bound_sj_equalities |= 1ULL << keyuse->sj_pred_no;
-            else
-            {
-              handled_sj_equalities |= 1ULL << keyuse->sj_pred_no;
-              sj_insideout_map |= ((key_part_map)1) << keyuse->keypart;
-              set_if_bigger(max_sj_keypart, keyuse->keypart);
-            }
-          }
-
+          loose_scan_opt.add_keyuse(remaining_tables, keyuse);
           keyuse++;
         } while (keyuse->table == table && keyuse->key == key &&
                  keyuse->keypart == keypart);
@@ -5586,13 +6138,12 @@ best_access_path(JOIN      *join,
       /*
         Assume that that each key matches a proportional part of table.
       */
-      if (!found_part && !ft_key && !handled_sj_equalities)
+      if (!found_part && !ft_key && !loose_scan_opt.have_a_case())
         continue;                               // Nothing usable found
 
       if (rec < MATCHING_ROWS_IN_OTHER_TABLE)
         rec= MATCHING_ROWS_IN_OTHER_TABLE;      // Fix for small tables
 
-      sj_inside_out_scan= MAX_KEY;
       /*
         ft-keys require special treatment
       */
@@ -5608,73 +6159,9 @@ best_access_path(JOIN      *join,
       else
       {
         found_constraint= test(found_part);
-        /*
-          Check if we can use InsideOut semi-join strategy. We can if
-          1. This is the right table at right location
-          2. All IN-equalities are either
-             - "bound", ie. the outer_expr part refers to the preceding tables
-             - "handled", ie. covered by the index we're considering
-          3. Index order allows to enumerate subquery's duplicate groups in
-             order. This happens when the index definition matches this
-             pattern:
-
-               (handled_col|bound_col)* (other_col|bound_col)
-
-        */
-        if (try_sj_inside_out &&                                    // (1)
-            (handled_sj_equalities | bound_sj_equalities) ==      // (2)
-            PREV_BITS(ulonglong, s->emb_sj_nest->sj_in_exprs) &&  // (2)
-            (PREV_BITS(key_part_map, max_sj_keypart+1) &           // (3)
-             (found_part | sj_insideout_map)) ==                     // (3)
-             (found_part | sj_insideout_map) &&                     // (3)
-            !key_uses_partial_cols(s->table, key))
-        {
-          /* Ok, can use the strategy */
-          sj_inside_out_scan= key;
-          if (s->quick && s->quick->index == key && 
-              s->quick->get_type() == QUICK_SELECT_I::QS_TYPE_RANGE)
-          {
-            sj_insideout_quick_select= TRUE;
-            sj_insideout_quick_max_sj_keypart= max_sj_keypart;
-          }
-          DBUG_PRINT("info", ("Can use InsideOut scan"));
-
-          /* 
-            Check if this is a confluent where there are no usable bound
-            IN-equalities, e.g. we have
+        loose_scan_opt.check_ref_access_part1(s, key, start_key, found_part);
 
-              outer_expr IN (SELECT innertbl.key FROM ...) 
-            
-            and outer_expr cannot be evaluated yet, so it's actually full
-            index scan and not a ref access
-          */
-          if (!(found_part & 1 ) && /* no usable ref access for 1st key part */
-              table->covering_keys.is_set(key))
-          {
-            DBUG_PRINT("info", ("Can use full index scan for InsideOut"));
-            /* Calculate the cost of complete loose index scan.  */
-            records= rows2double(s->table->file->stats.records);
-
-            /* The cost is entire index scan cost (divided by 2) */
-            best_time= s->table->file->index_only_read_time(key, records);
-
-            /*
-              Now find out how many different keys we will get (for now we
-              ignore the fact that we have "keypart_i=const" restriction for
-              some key components, that may make us think think that loose
-              scan will produce more distinct records than it actually will)
-            */
-            ulong rpc;
-            if ((rpc= keyinfo->rec_per_key[max_sj_keypart]))
-              records= records / rpc;
-            start_key= NULL;
-            /* Fall through */
-          }
-        }
-
-        /*
-          Check if we found full key
-        */
+        /* Check if we found full key */
         if (found_part == PREV_BITS(uint,keyinfo->key_parts) &&
             !ref_or_null_part)
         {                                         /* use eq key */
@@ -5922,13 +6409,7 @@ best_access_path(JOIN      *join,
           else
             tmp= best_time;                    // Do nothing
         }
-
-        if ((sj_inside_out_scan != MAX_KEY) && !start_key)
-        {
-          tmp= tmp/2;
-          if (records)
-            records= records/2;
-        }
+        loose_scan_opt.check_ref_access_part2(key, start_key, records, tmp);
 
       } /* not ft_key */
       if (tmp < best_time - records/(double) TIME_FOR_COMPARE)
@@ -5939,8 +6420,6 @@ best_access_path(JOIN      *join,
         best_key= start_key;
         best_max_key_part= max_key_part;
         best_ref_depends_map= found_ref;
-        best_is_sj_inside_out= sj_inside_out_scan;
-        best_sj_keyparts= max_sj_keypart;
       }
     } /* for each key */
     records= best_records;
@@ -5981,7 +6460,6 @@ best_access_path(JOIN      *join,
         ! s->table->covering_keys.is_clear_all() && best_key && !s->quick) &&// (3)
       !(s->table->force_index && best_key && !s->quick))                 // (4)
   {                                             // Check full join
-    sj_inside_out_scan= MAX_KEY;
     ha_rows rnd_records= s->found_records;
     /*
       If there is a filtering condition on the table (i.e. ref analyzer found
@@ -6007,6 +6485,7 @@ best_access_path(JOIN      *join,
       than FULL: so if RANGE is present, it's always preferred to FULL.
       Here we estimate its cost.
     */
+
     if (s->quick)
     {
       /*
@@ -6021,17 +6500,14 @@ best_access_path(JOIN      *join,
       tmp= record_count *
         (s->quick->read_time +
          (s->found_records - rnd_records)/(double) TIME_FOR_COMPARE);
-      
-      if (sj_insideout_quick_select && idx == join->const_tables)
-      {
-        sj_inside_out_scan= s->quick->index;
-      }
+
+      loose_scan_opt.check_range_access(join, idx, s->quick);
     }
     else
     {
       /* Estimate cost of reading table. */
       tmp= s->table->file->scan_time();
-      if (s->table->map & join->outer_join)     // Can't use join cache
+      if ((s->table->map & join->outer_join) || disable_jbuf)     // Can't use join cache
       {
         /*
           For each record we have to:
@@ -6077,19 +6553,21 @@ best_access_path(JOIN      *join,
       best_key= 0;
       /* range/index_merge/ALL/index access method are "independent", so: */
       best_ref_depends_map= 0;
-      best_is_sj_inside_out= sj_inside_out_scan;
-      best_sj_keyparts= sj_insideout_quick_max_sj_keypart;
+      best_uses_jbuf= test(!disable_jbuf && !((s->table->map & 
+                                               join->outer_join)));
     }
   }
-
+  
   /* Update the cost information for the current partial plan */
-  join->positions[idx].records_read= records;
-  join->positions[idx].read_time=    best;
-  join->positions[idx].key=          best_key;
-  join->positions[idx].table=        s;
-  join->positions[idx].ref_depend_map= best_ref_depends_map;
-  join->positions[idx].insideout_key= best_is_sj_inside_out;
-  join->positions[idx].insideout_parts= best_sj_keyparts + 1;
+  pos->records_read= records;
+  pos->read_time=    best;
+  pos->key=          best_key;
+  pos->table=        s;
+  pos->ref_depend_map= best_ref_depends_map;
+  pos->loosescan_key= MAX_KEY;
+  pos->use_join_buffer= best_uses_jbuf;
+   
+  loose_scan_opt.save_to_position(s, loose_scan_pos);
 
   if (!best_key &&
       idx == join->const_tables &&
@@ -6114,6 +6592,9 @@ best_access_path(JOIN      *join,
                       the query
   @param join_tables  set of the tables in the query
 
+  @param sj_nest      If not NULL, optimize a subjoin of tables within the
+                      given semi-join nest.
+
   @todo
     'MAX_TABLES+2' denotes the old implementation of find_best before
     the greedy version. Will be removed when greedy_search is approved.
@@ -6133,19 +6614,73 @@ choose_plan(JOIN *join, table_map join_t
   DBUG_ENTER("choose_plan");
 
   join->cur_embedding_map= 0;
+  join->cur_dups_producing_tables= 0;
   reset_nj_counters(join->join_list);
-  /*
-    if (SELECT_STRAIGHT_JOIN option is set)
-      reorder tables so dependent tables come after tables they depend 
-      on, otherwise keep tables in the order they were specified in the query 
-    else
-      Apply heuristic: pre-sort all access plans with respect to the number of
-      records accessed.
-  */
-  my_qsort(join->best_ref + join->const_tables,
-           join->tables - join->const_tables, sizeof(JOIN_TAB*),
-           straight_join ? join_tab_cmp_straight : join_tab_cmp);
-  join->cur_emb_sj_nests= 0;
+  qsort2_cmp jtab_sort_func;
+
+  if (join->emb_sjm_nest)
+  {
+    /* We're optimizing semi-join materialization nest, so put the 
+       tables from this semi-join as first
+    */
+    jtab_sort_func= join_tab_cmp_embedded_first;
+  }
+  else
+  {
+    /*
+      if (SELECT_STRAIGHT_JOIN option is set)
+        reorder tables so dependent tables come after tables they depend 
+        on, otherwise keep tables in the order they were specified in the query 
+      else
+        Apply heuristic: pre-sort all access plans with respect to the number of
+        records accessed.
+    */
+    jtab_sort_func= straight_join ? join_tab_cmp_straight : join_tab_cmp;
+  }
+  my_qsort2(join->best_ref + join->const_tables,
+            join->tables - join->const_tables, sizeof(JOIN_TAB*),
+            jtab_sort_func, (void*)join->emb_sjm_nest);
+  join->cur_sj_inner_tables= 0;
+
+#if 0
+  if (!join->emb_sjm_nest && straight_join)
+  {
+    /* Put all sj-inner tables right after their last outer table table.  */
+    uint inner;
+
+    /* Find the first inner table (inner tables follow outer) */
+    for (inner= join->const_tables;
+         inner < join->tables && !join->best_ref[inner]->emb_sj_nest;
+         inner++);
+
+    while (inner < join->tables) /* for each group of inner tables... */
+    {
+      TABLE_LIST *emb_sj_nest= join->best_ref[inner]->emb_sj_nest;
+      uint n_tables= my_count_bits(emb_sj_nest->sj_inner_tables);
+      table_map cur_map= join->const_table_map;
+      table_map needed_map= emb_sj_nest->nested_join->sj_depends_on |
+                            emb_sj_nest->nested_join->sj_corr_tables;
+      /* Locate the last outer table with which this semi-join is correlated */
+      uint last_outer;
+      for (last_outer= join->const_tables; last_outer < inner; last_outer++)
+      {
+        cur_map |= join->best_ref[last_outer]->table->map;
+        if (!(needed_map & ~cur_map))
+          break;
+      }
+      /* Move the inner tables to here */
+      JOIN_TAB *tmp[MAX_TABLES];
+      memcpy(tmp, join->best_ref + inner, n_tables*sizeof(JOIN_TAB));
+      for (uint i= inner - 1; i > last_outer; i--)
+      {
+        join->best_ref[i + n_tables]= join->best_ref[i]; 
+      }
+      memcpy(join->best_ref + last_outer + 1, tmp, n_tables*sizeof(JOIN_TAB));
+      inner += n_tables;
+    }
+  }
+#endif
+
   if (straight_join)
   {
     optimize_straight_join(join, join_tables);
@@ -6209,7 +6744,7 @@ choose_plan(JOIN *join, table_map join_t
 */
 
 static int
-join_tab_cmp(const void* ptr1, const void* ptr2)
+join_tab_cmp(const void *dummy, const void* ptr1, const void* ptr2)
 {
   JOIN_TAB *jt1= *(JOIN_TAB**) ptr1;
   JOIN_TAB *jt2= *(JOIN_TAB**) ptr2;
@@ -6231,10 +6766,18 @@ join_tab_cmp(const void* ptr1, const voi
 */
 
 static int
-join_tab_cmp_straight(const void* ptr1, const void* ptr2)
+join_tab_cmp_straight(const void *dummy, const void* ptr1, const void* ptr2)
 {
   JOIN_TAB *jt1= *(JOIN_TAB**) ptr1;
   JOIN_TAB *jt2= *(JOIN_TAB**) ptr2;
+ 
+  /*
+    We don't do subquery flattening if the parent or child select has
+    STRAIGHT_JOIN modifier. It is complicated to implement and the semantics
+    is hardly useful.
+  */
+  DBUG_ASSERT(!jt1->emb_sj_nest);
+  DBUG_ASSERT(!jt2->emb_sj_nest);
 
   if (jt1->dependent & jt2->table->map)
     return 1;
@@ -6243,6 +6786,38 @@ join_tab_cmp_straight(const void* ptr1,
   return jt1 > jt2 ? 1 : (jt1 < jt2 ? -1 : 0);
 }
 
+
+/*
+  Same as join_tab_cmp but tables from within the given semi-join nest go 
+  first. Used when the optimizing semi-join materialization nests.
+*/
+
+static int
+join_tab_cmp_embedded_first(const void *emb,  const void* ptr1, const void* ptr2)
+{
+  const TABLE_LIST *emb_nest= (TABLE_LIST*) emb;
+  JOIN_TAB *jt1= *(JOIN_TAB**) ptr1;
+  JOIN_TAB *jt2= *(JOIN_TAB**) ptr2;
+
+  if (jt1->emb_sj_nest == emb_nest && jt2->emb_sj_nest != emb_nest)
+    return -1;
+  if (jt1->emb_sj_nest != emb_nest && jt2->emb_sj_nest == emb_nest)
+    return 1;
+
+  if (jt1->dependent & jt2->table->map)
+    return 1;
+  if (jt2->dependent & jt1->table->map)
+    return -1;
+
+  if (jt1->found_records > jt2->found_records)
+    return 1;
+  if (jt1->found_records < jt2->found_records)
+    return -1; 
+  
+  return jt1 > jt2 ? 1 : (jt1 < jt2 ? -1 : 0);
+}
+
+
 /**
   Heuristic procedure to automatically guess a reasonable degree of
   exhaustiveness for the greedy search procedure.
@@ -6326,30 +6901,88 @@ optimize_straight_join(JOIN *join, table
   uint idx= join->const_tables;
   double    record_count= 1.0;
   double    read_time=    0.0;
+  POSITION  loose_scan_pos;
  
   for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
   {
     /* Find the best access method from 's' to the current partial plan */
-    advance_sj_state(join_tables, s);
-    best_access_path(join, s, join->thd, join_tables, idx,
-                     record_count, read_time);
+    best_access_path(join, s, join_tables, idx, FALSE, record_count,
+                     join->positions + idx, &loose_scan_pos);
+
     /* compute the cost of the new plan extended with 's' */
     record_count*= join->positions[idx].records_read;
     read_time+=    join->positions[idx].read_time;
+    advance_sj_state(join, join_tables, s, idx, &record_count, &read_time,
+                     &loose_scan_pos);
+
     join_tables&= ~(s->table->map);
     ++idx;
   }
-
-  read_time+= record_count / (double) TIME_FOR_COMPARE;
-  if (join->sort_by_table &&
-      join->sort_by_table != join->positions[join->const_tables].table->table)
-    read_time+= record_count;  // We have to make a temp table
-  memcpy((uchar*) join->best_positions, (uchar*) join->positions,
-         sizeof(POSITION)*idx);
-  join->best_read= read_time;
+
+  read_time+= record_count / (double) TIME_FOR_COMPARE;
+  if (join->sort_by_table &&
+      join->sort_by_table != join->positions[join->const_tables].table->table)
+    read_time+= record_count;  // We have to make a temp table
+  memcpy((uchar*) join->best_positions, (uchar*) join->positions,
+         sizeof(POSITION)*idx);
+  join->best_read= read_time;
+}
+
+
+/*
+  Check if the last tables of the partial join order allow to use
+  sj-materialization strategy for them
+
+  SYNOPSIS
+    at_sjmat_pos()
+      join              
+      remaining_tables
+      tab                the last table's join tab
+      idx                last table's index
+      loose_scan    OUT  TRUE <=> use LooseScan
+
+  RETURN
+    TRUE   Yes, can apply sj-materialization
+    FALSE  No, some of the requirements are not met
+*/
+
+SJ_MATERIALIZATION_INFO *
+at_sjmat_pos(const JOIN *join, table_map remaining_tables, const JOIN_TAB *tab,
+             uint idx, bool *loose_scan)
+{
+  /*
+   Check if 
+    1. We're in a semi-join nest that can be run with SJ-materialization
+    2. All the tables correlated through the IN subquery are in the prefix
+  */
+  TABLE_LIST *emb_sj_nest= tab->emb_sj_nest;
+  table_map suffix= remaining_tables & ~tab->table->map;
+  if (emb_sj_nest && emb_sj_nest->sj_mat_info &&
+      !(suffix & emb_sj_nest->sj_inner_tables))
+  {
+    /* 
+      Walk back and check if all immediately preceding tables are from
+      this semi-join.
+    */
+    uint n_tables= my_count_bits(tab->emb_sj_nest->sj_inner_tables);
+    for (uint i= 1; i < n_tables ; i++)
+    {
+      if (join->positions[idx - i].table->emb_sj_nest != tab->emb_sj_nest)
+        return NULL;
+    }
+    *loose_scan= test(remaining_tables & ~tab->table->map &
+                             (emb_sj_nest->sj_inner_tables |
+                              emb_sj_nest->nested_join->sj_depends_on));
+    if (*loose_scan && !emb_sj_nest->sj_subq_pred->sjm_scan_allowed)
+      return NULL;
+    else
+      return emb_sj_nest->sj_mat_info;
+  }
+  return NULL;
 }
 
 
+
 /**
   Find a good, possibly optimal, query execution plan (QEP) by a greedy search.
 
@@ -6444,11 +7077,15 @@ greedy_search(JOIN      *join,
   uint      size_remain;    // cardinality of remaining_tables
   POSITION  best_pos;
   JOIN_TAB  *best_table; // the next plan node to be added to the curr QEP
+  uint      n_tables; // ==join->tables or # tables in the sj-mat nest we're optimizing
 
   DBUG_ENTER("greedy_search");
 
   /* number of tables that remain to be optimized */
-  size_remain= my_count_bits(remaining_tables);
+  n_tables= size_remain= my_count_bits(remaining_tables &
+                                       (join->emb_sjm_nest? 
+                                         join->emb_sjm_nest->sj_inner_tables :
+                                         ~(table_map)0));
 
   do {
     /* Find the extension of the current QEP with the lowest cost */
@@ -6463,9 +7100,8 @@ greedy_search(JOIN      *join,
         'join->best_positions' contains a complete optimal extension of the
         current partial QEP.
       */
-      DBUG_EXECUTE("opt", print_plan(join, join->tables,
-                                     record_count, read_time, read_time,
-                                     "optimal"););
+      DBUG_EXECUTE("opt", print_plan(join, n_tables, record_count, read_time,
+                                     read_time, "optimal"););
       DBUG_RETURN(FALSE);
     }
 
@@ -6496,13 +7132,53 @@ greedy_search(JOIN      *join,
     --size_remain;
     ++idx;
 
-    DBUG_EXECUTE("opt", print_plan(join, join->tables,
-                                   record_count, read_time, read_time,
-                                   "extended"););
+    DBUG_EXECUTE("opt", print_plan(join, n_tables, record_count, read_time, 
+                                   read_time, "extended"););
   } while (TRUE);
 }
 
 
+/*
+  Calculate a cost of given partial join order
+ 
+  SYNOPSIS
+    get_partial_join_cost()
+      join               IN    Join to use. join->positions holds the
+                               partial join order
+      idx                IN    # tables in the partial join order
+      read_time_arg      OUT   Store read time here 
+      record_count_arg   OUT   Store record count here
+
+  DESCRIPTION
+
+    This is needed for semi-join materialization code. The idea is that 
+    we detect sj-materialization after we've put all sj-inner tables into
+    the join prefix
+
+      prefix-tables semi-join-inner-tables  tN
+                                             ^--we're here
+
+    and we'll need to get the cost of prefix-tables prefix again.
+*/
+
+void get_partial_join_cost(JOIN *join, uint n_tables, double *read_time_arg,
+                           double *record_count_arg)
+{
+  double record_count= 1;
+  double read_time= 0.0;
+  for (uint i= join->const_tables; i < n_tables + join->const_tables ; i++)
+  {
+    if (join->best_positions[i].records_read)
+    {
+      record_count *= join->best_positions[i].records_read;
+      read_time += join->best_positions[i].read_time;
+    }
+  }
+  *read_time_arg= read_time;// + record_count / TIME_FOR_COMPARE;
+  *record_count_arg= record_count;
+}
+
+
 /**
   Find a good, possibly optimal, query execution plan (QEP) by a possibly
   exhaustive search.
@@ -6649,22 +7325,33 @@ best_extension_by_limited_search(JOIN
   DBUG_EXECUTE("opt", print_plan(join, idx, record_count, read_time, read_time,
                                 "part_plan"););
 
+  table_map allowed_tables= ~(table_map)0;
+  if (join->emb_sjm_nest)
+    allowed_tables= join->emb_sjm_nest->sj_inner_tables;
+
   for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
   {
     table_map real_table_bit= s->table->map;
     if ((remaining_tables & real_table_bit) && 
+        (allowed_tables & real_table_bit) &&
         !(remaining_tables & s->dependent) && 
         (!idx || !check_interleaving_with_nj(join->positions[idx-1].table, s)))
     {
       double current_record_count, current_read_time;
-      advance_sj_state(remaining_tables, s);
+      POSITION *position= join->positions + idx;
 
       /* Find the best access method from 's' to the current partial plan */
-      best_access_path(join, s, thd, remaining_tables, idx,
-                       record_count, read_time);
+      POSITION loose_scan_pos;
+      best_access_path(join, s, remaining_tables, idx, FALSE, record_count, 
+                       join->positions + idx, &loose_scan_pos);
+
       /* Compute the cost of extending the plan with 's' */
-      current_record_count= record_count * join->positions[idx].records_read;
-      current_read_time=    read_time + join->positions[idx].read_time;
+
+      current_record_count= record_count * position->records_read;
+      current_read_time=    read_time + position->read_time;
+
+      advance_sj_state(join, remaining_tables, s, idx, &current_record_count,
+                       &current_read_time, &loose_scan_pos);
 
       /* Expand only partial plans with lower cost than the best QEP so far */
       if ((current_read_time +
@@ -6678,7 +7365,7 @@ best_extension_by_limited_search(JOIN
                                         (double) TIME_FOR_COMPARE),
                                        "prune_by_cost"););
         restore_prev_nj_state(s);
-        restore_prev_sj_state(remaining_tables, s);
+        restore_prev_sj_state(remaining_tables, s, idx);
         continue;
       }
 
@@ -6711,12 +7398,12 @@ best_extension_by_limited_search(JOIN
                                          current_read_time,
                                          "pruned_by_heuristic"););
           restore_prev_nj_state(s);
-          restore_prev_sj_state(remaining_tables, s);
+          restore_prev_sj_state(remaining_tables, s, idx);
           continue;
         }
       }
 
-      if ( (search_depth > 1) && (remaining_tables & ~real_table_bit) )
+      if ( (search_depth > 1) && (remaining_tables & ~real_table_bit) & allowed_tables )
       { /* Recursively expand the current partial plan */
         swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
         if (best_extension_by_limited_search(join,
@@ -6753,7 +7440,7 @@ best_extension_by_limited_search(JOIN
                                        "full_plan"););
       }
       restore_prev_nj_state(s);
-      restore_prev_sj_state(remaining_tables, s);
+      restore_prev_sj_state(remaining_tables, s, idx);
     }
   }
   DBUG_RETURN(FALSE);
@@ -6807,9 +7494,9 @@ find_best(JOIN *join,table_map rest_tabl
         (!idx|| !check_interleaving_with_nj(join->positions[idx-1].table, s)))
     {
       double records, best;
-      advance_sj_state(rest_tables, s);
-      best_access_path(join, s, thd, rest_tables, idx, record_count, 
-                       read_time);
+      POSITION loose_scan_pos;
+      best_access_path(join, s, rest_tables, idx, FALSE, record_count, 
+                       join->positions + idx, &loose_scan_pos);
       records= join->positions[idx].records_read;
       best= join->positions[idx].read_time;
       /*
@@ -6818,6 +7505,9 @@ find_best(JOIN *join,table_map rest_tabl
       */
       double current_record_count=record_count*records;
       double current_read_time=read_time+best;
+      advance_sj_state(join, rest_tables, s, idx, &current_record_count, 
+                       &current_read_time, &loose_scan_pos);
+
       if (best_record_count > current_record_count ||
 	  best_read_time > current_read_time ||
 	  idx == join->const_tables && s->table == join->sort_by_table)
@@ -6836,7 +7526,7 @@ find_best(JOIN *join,table_map rest_tabl
 	swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
       }
       restore_prev_nj_state(s);
-      restore_prev_sj_state(rest_tables, s);
+      restore_prev_sj_state(rest_tables, s, idx);
       if (join->select_options & SELECT_STRAIGHT_JOIN)
 	break;				// Don't test all combinations
     }
@@ -6991,12 +7681,231 @@ prev_record_reads(JOIN *join, uint idx,
 }
 
 
-/**
+/*
+  Fix semi-join strategies for the picked join order
+
+  SYNOPSIS
+    fix_semijoin_strategies_for_picked_join_order()
+      join  The join with the picked join order
+
+  DESCRIPTION
+    Fix semi-join strategies for the picked join order. This is a step that
+    needs to be done right after we have fixed the join order. What we do
+    here is switch join's semi-join strategy description from backward-based
+    to forwards based.
+    
+    When join optimization is in progress, we re-consider semi-join
+    strategies after we've added another table. Here's an illustration.
+    Suppose the join optimization is underway:
+
+    1) ot1  it1  it2 
+                 sjX  -- looking at (ot1, it1, it2) join prefix, we decide
+                         to use semi-join strategy sjX.
+
+    2) ot1  it1  it2  ot2 
+                 sjX  sjY -- Having added table ot2, we now may consider
+                             another semi-join strategy and decide to use a 
+                             different strategy sjY. Note that the record
+                             of sjX has remained under it2. That is
+                             necessary because we need to be able to get
+                             back to (ot1, it1, it2) join prefix.
+      what makes things even worse is that there are cases where the choice
+      of sjY changes the way we should access it2. 
+
+    3) [ot1  it1  it2  ot2  ot3]
+                  sjX  sjY  -- This means that after join optimization is
+                               finished, semi-join info should be read
+                               right-to-left (while nearly all plan refinement
+                               functions, EXPLAIN, etc proceed from left to 
+                               right)
+
+    This function does the needed reversal, making it possible to read the
+    join and semi-join order from left to right.
+*/    
+
+static void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
+{
+  uint table_count=join->tables;
+  uint tablenr;
+  table_map remaining_tables= 0;
+  table_map handled_tabs= 0;
+  for (tablenr= table_count - 1 ; tablenr != join->const_tables - 1; tablenr--)
+  {
+    POSITION *pos= join->best_positions + tablenr;
+    JOIN_TAB *s= pos->table;
+    uint first;
+    LINT_INIT(first); // Set by every branch except SJ_OPT_NONE which doesn't use it
+
+    if ((handled_tabs & s->table->map) || pos->sj_strategy == SJ_OPT_NONE)
+    {
+      remaining_tables |= s->table->map;
+      continue;
+    }
+    
+    if (pos->sj_strategy == SJ_OPT_MATERIALIZE)
+    {
+      SJ_MATERIALIZATION_INFO *sjm= s->emb_sj_nest->sj_mat_info;
+      sjm->is_used= TRUE;
+      sjm->is_sj_scan= FALSE;
+      memcpy(pos - sjm->tables + 1, sjm->positions, 
+             sizeof(POSITION) * sjm->tables);
+      first= tablenr - sjm->tables + 1;
+      join->best_positions[first].n_sj_tables= sjm->tables;
+      join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE;
+    }
+    else if (pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN)
+    {
+      POSITION *first_inner= join->best_positions + pos->sjm_scan_last_inner;
+      SJ_MATERIALIZATION_INFO *sjm= first_inner->table->emb_sj_nest->sj_mat_info;
+      sjm->is_used= TRUE;
+      sjm->is_sj_scan= TRUE;
+      first= pos->sjm_scan_last_inner - sjm->tables + 1;
+      memcpy(join->best_positions + first, 
+             sjm->positions, sizeof(POSITION) * sjm->tables);
+      join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE_SCAN;
+      join->best_positions[first].n_sj_tables= sjm->tables;
+      /* 
+        Do what advance_sj_state did: re-run best_access_path for every table
+        in the [last_inner_table + 1; pos..) range
+      */
+      double prefix_rec_count;
+      /* Get the prefix record count */
+      if (first == join->const_tables)
+        prefix_rec_count= 1.0;
+      else
+        prefix_rec_count= join->best_positions[first-1].prefix_record_count;
+      
+      /* Add materialization record count*/
+      prefix_rec_count *= sjm->rows;
+      
+      uint i;
+      table_map rem_tables= remaining_tables;
+      for (i= tablenr; i != (first + sjm->tables - 1); i--)
+        rem_tables |= join->best_positions[i].table->table->map;
+
+      POSITION dummy;
+      join->cur_sj_inner_tables= 0;
+      for (i= first + sjm->tables; i <= tablenr; i++)
+      {
+        best_access_path(join, join->best_positions[i].table, rem_tables, i, FALSE,
+                         prefix_rec_count, join->best_positions + i, &dummy);
+        prefix_rec_count *= join->best_positions[i].records_read;
+        rem_tables &= ~join->best_positions[i].table->table->map;
+      }
+    }
+ 
+    if (pos->sj_strategy == SJ_OPT_FIRST_MATCH)
+    {
+      first= pos->first_firstmatch_table;
+      join->best_positions[first].sj_strategy= SJ_OPT_FIRST_MATCH;
+      join->best_positions[first].n_sj_tables= tablenr - first + 1;
+      POSITION dummy; // For loose scan paths
+      double record_count= (first== join->const_tables)? 1.0: 
+                           join->best_positions[tablenr - 1].prefix_record_count;
+      
+      table_map rem_tables= remaining_tables;
+      uint idx;
+      for (idx= first; idx <= tablenr; idx++)
+      {
+        rem_tables |= join->best_positions[idx].table->table->map;
+      }
+      /*
+        Re-run best_access_path to produce best access methods that do not use
+        join buffering
+      */ 
+      join->cur_sj_inner_tables= 0;
+      for (idx= first; idx <= tablenr; idx++)
+      {
+        if (join->best_positions[idx].use_join_buffer)
+        {
+           best_access_path(join, join->best_positions[idx].table, 
+                            rem_tables, idx, TRUE /* no jbuf */,
+                            record_count, join->best_positions + idx, &dummy);
+        }
+        record_count *= join->best_positions[idx].records_read;
+        rem_tables &= ~join->best_positions[idx].table->table->map;
+      }
+    }
+
+    if (pos->sj_strategy == SJ_OPT_LOOSE_SCAN) 
+    {
+      first= pos->first_loosescan_table;
+      POSITION *first_pos= join->best_positions + first;
+      POSITION loose_scan_pos; // For loose scan paths
+      double record_count= (first== join->const_tables)? 1.0: 
+                           join->best_positions[tablenr - 1].prefix_record_count;
+      
+      table_map rem_tables= remaining_tables;
+      uint idx;
+      for (idx= first; idx <= tablenr; idx++)
+        rem_tables |= join->best_positions[idx].table->table->map;
+      /*
+        Re-run best_access_path to produce best access methods that do not use
+        join buffering
+      */ 
+      join->cur_sj_inner_tables= 0;
+      for (idx= first; idx <= tablenr; idx++)
+      {
+        if (join->best_positions[idx].use_join_buffer || (idx == first))
+        {
+           best_access_path(join, join->best_positions[idx].table,
+                            rem_tables, idx, TRUE /* no jbuf */,
+                            record_count, join->best_positions + idx,
+                            &loose_scan_pos);
+           if (idx==first)
+             join->best_positions[idx]= loose_scan_pos;
+        }
+        rem_tables &= ~join->best_positions[idx].table->table->map;
+        record_count *= join->best_positions[idx].records_read;
+      }
+      first_pos->sj_strategy= SJ_OPT_LOOSE_SCAN;
+      first_pos->n_sj_tables= my_count_bits(first_pos->table->emb_sj_nest->sj_inner_tables);
+    }
+
+    if (pos->sj_strategy == SJ_OPT_DUPS_WEEDOUT)
+    {
+      /* 
+        Duplicate Weedout starting at pos->first_dupsweedout_table, ending at
+        this table.
+      */
+      first= pos->first_dupsweedout_table;
+      join->best_positions[first].sj_strategy= SJ_OPT_DUPS_WEEDOUT;
+      join->best_positions[first].n_sj_tables= tablenr - first + 1;
+    }
+    
+    uint i_end= first + join->best_positions[first].n_sj_tables;
+    for (uint i= first; i < i_end; i++)
+      handled_tabs |= join->best_positions[i].table->table->map;
+
+    if (tablenr != first)
+      pos->sj_strategy= SJ_OPT_NONE;
+    remaining_tables |= s->table->map;
+  }
+}
+
+
+/*
   Set up join struct according to best position.
+  
+  SYNOPSIS
+    get_best_combination()
+      join  The join to process
+
+  DESCRIPTION
+    Setup join structures according the picked join order:
+    - finalize semi-join strategy choices (see
+        fix_semijoin_strategies_for_picked_join_order)
+
+    - create join->join_tab array and put there the JOIN_TABs in the join order
+      
+    - create ref access data structures
+
+  RETURN 
+    FALSE  OK
+    TRUE   Out of memory
 */
 
-static bool
-get_best_combination(JOIN *join)
+static bool get_best_combination(JOIN *join)
 {
   uint i,tablenr;
   table_map used_tables;
@@ -7014,6 +7923,9 @@ get_best_combination(JOIN *join)
   join->full_join=0;
 
   used_tables= OUTER_REF_TABLE_BIT;		// Outer row is already read
+
+  fix_semijoin_strategies_for_picked_join_order(join);
+
   for (j=join_tab, tablenr=0 ; tablenr < table_count ; tablenr++,j++)
   {
     TABLE *form;
@@ -7024,18 +7936,22 @@ get_best_combination(JOIN *join)
     if (!*j->on_expr_ref)
       form->reginfo.not_exists_optimize=0;	// Only with LEFT JOIN
     DBUG_PRINT("info",("type: %d", j->type));
+
     if (j->type == JT_CONST)
       continue;					// Handled in make_join_stat..
-    j->insideout_match_tab= NULL;
+
+    j->loosescan_match_tab= NULL;  //non-nulls will be set later
     j->ref.key = -1;
     j->ref.key_parts=0;
 
+
     if (j->type == JT_SYSTEM)
       continue;
-    if (j->keys.is_clear_all() || !(keyuse= join->best_positions[tablenr].key))
+    if (j->keys.is_clear_all() || !(keyuse= join->best_positions[tablenr].key) || 
+        (join->best_positions[tablenr].sj_strategy == SJ_OPT_LOOSE_SCAN))
     {
       j->type=JT_ALL;
-      j->index= join->best_positions[tablenr].insideout_key;
+      j->index= join->best_positions[tablenr].loosescan_key;
       if (tablenr != join->const_tables)
 	join->full_join=1;
     }
@@ -7330,9 +8246,11 @@ make_simple_join(JOIN *join,TABLE *tmp_t
   join_tab->read_first_record= join_init_read_record;
   join_tab->join=join;
   join_tab->ref.key_parts= 0;
+  join_tab->keep_current_rowid= FALSE;
   join_tab->flush_weedout_table= join_tab->check_weed_out_table= NULL;
   join_tab->do_firstmatch= NULL;
-  join_tab->insideout_match_tab= NULL;
+  join_tab->loosescan_match_tab= NULL;
+  join_tab->emb_sj_nest= NULL;
   bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record));
   tmp_table->status=0;
   tmp_table->null_row=0;
@@ -7584,15 +8502,19 @@ make_outerjoin_info(JOIN *join)
 }
 
 
-static bool
-make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
+static bool make_join_select(JOIN *join, Item *cond)
 {
   THD *thd= join->thd;
   DBUG_ENTER("make_join_select");
-  if (select)
   {
     add_not_null_conds(join);
     table_map used_tables;
+    /*
+      Step #1: Extract constant condition
+       - Extract and check the constant part of the WHERE 
+       - Extract constant parts of ON expressions from outer 
+         joins and attach them appropriately.
+    */
     if (cond)                /* Because of QUICK_GROUP_MIN_MAX_SELECT */
     {                        /* there may be a select without a cond. */    
       if (join->tables > 1)
@@ -7645,20 +8567,41 @@ make_join_select(JOIN *join,SQL_SELECT *
         }
       }
     }
-    used_tables=((select->const_tables=join->const_table_map) |
-		 OUTER_REF_TABLE_BIT | RAND_TABLE_BIT);
+
+    /*
+      Step #2: Extract WHERE/ON parts
+    */
+    table_map save_used_tables= 0;
+    used_tables= join->const_table_map | OUTER_REF_TABLE_BIT | RAND_TABLE_BIT;
+    JOIN_TAB *tab;
+    table_map current_map;
     for (uint i=join->const_tables ; i < join->tables ; i++)
     {
-      JOIN_TAB *tab=join->join_tab+i;
+      tab= join->join_tab+i;
       /*
         first_inner is the X in queries like:
         SELECT * FROM t1 LEFT OUTER JOIN (t2 JOIN t3) ON X
       */
       JOIN_TAB *first_inner_tab= tab->first_inner; 
-      table_map current_map= tab->table->map;
+      current_map= tab->table->map;
       bool use_quick_range=0;
       COND *tmp;
 
+      /* 
+        Tables that are within SJ-Materialization nests cannot have their
+        conditions referring to preceding non-const tables.
+         - If we're looking at the first SJM table, reset used_tables
+           to refer to only allowed tables
+      */
+      if (tab->emb_sj_nest && tab->emb_sj_nest->sj_mat_info && 
+          tab->emb_sj_nest->sj_mat_info->is_used &&
+          !(used_tables & tab->emb_sj_nest->sj_inner_tables))
+      {
+        save_used_tables= used_tables;
+        used_tables= join->const_table_map | OUTER_REF_TABLE_BIT | 
+                     RAND_TABLE_BIT;
+      }
+
       /*
 	Following force including random expression in last table condition.
 	It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5
@@ -7717,11 +8660,10 @@ make_join_select(JOIN *join,SQL_SELECT *
           tab->type == JT_EQ_REF || first_inner_tab)
       {
         DBUG_EXECUTE("where",print_where(tmp,tab->table->alias, QT_ORDINARY););
-	SQL_SELECT *sel= tab->select= ((SQL_SELECT*)
-                                       thd->memdup((uchar*) select,
-                                                   sizeof(*select)));
+	SQL_SELECT *sel= tab->select= new (thd->mem_root) SQL_SELECT;
 	if (!sel)
 	  DBUG_RETURN(1);			// End of memory
+        sel->read_tables= sel->const_tables= join->const_table_map;
         /*
           If tab is an inner table of an outer join operation,
           add a match guard to the pushed down predicate.
@@ -7889,7 +8831,6 @@ make_join_select(JOIN *join,SQL_SELECT *
         'on expression' are guaranteed not to be checked for
         the null complemented row.
       */ 
-
       /* First push down constant conditions from on expressions */
       for (JOIN_TAB *join_tab= join->join_tab+join->const_tables;
            join_tab < join->join_tab+join->tables ; join_tab++)
@@ -7975,6 +8916,33 @@ make_join_select(JOIN *join,SQL_SELECT *
         }
         first_inner_tab= first_inner_tab->first_upper;       
       }
+
+      if (save_used_tables && !(used_tables & 
+                                ~(tab->emb_sj_nest->sj_inner_tables |
+                                  join->const_table_map | PSEUDO_TABLE_BITS)))
+      {
+        /*
+          We have reached the end of semi join nest. That is, the join order
+          looks like this:
+
+           outer_tbl1 SJ-Materialize(inner_tbl1 ... inner_tblN) outer_tbl ...
+                                                               ^
+                                                                \-we're here
+          At this point, we need to produce two conditions
+           - A condition that can be checked when we have all of the sj-inner
+             tables (inner_tbl1 ... inner_tblN). This will be used while doing
+             materialization.
+           - A condition that can be checked when we have all of the tables
+             in the prefix (both inner and outer).
+        */
+        tab->emb_sj_nest->sj_mat_info->join_cond= 
+          cond ?
+             make_cond_after_sjm(cond, cond, save_used_tables, used_tables):
+            NULL;
+        used_tables= save_used_tables | used_tables;
+        save_used_tables= 0;
+      }
+
     }
   }
   DBUG_RETURN(0);
@@ -8305,16 +9273,29 @@ static void push_index_cond(JOIN_TAB *ta
 
 
 
-    /*
-      Determine if the set is already ordered for ORDER BY, so it can 
-      disable join cache because it will change the ordering of the results.
-      Code handles sort table that is at any location (not only first after 
-      the const tables) despite the fact that it's currently prohibited.
-      We must disable join cache if the first non-const table alone is
-      ordered. If there is a temp table the ordering is done as a last
-      operation and doesn't prevent join cache usage.
-    */
-uint make_join_orderinfo(JOIN *join)
+/*
+  Determine {after which table we'll produce ordered set} 
+
+  SYNOPSIS
+    make_join_orderinfo()
+     join
+
+   
+  DESCRIPTION 
+    Determine if the set is already ordered for ORDER BY, so it can 
+    disable join cache because it will change the ordering of the results.
+    Code handles sort table that is at any location (not only first after 
+    the const tables) despite the fact that it's currently prohibited.
+    We must disable join cache if the first non-const table alone is
+    ordered. If there is a temp table the ordering is done as a last
+    operation and doesn't prevent join cache usage.
+
+  RETURN
+    Number of table after which the set will be ordered
+    join->tables if we don't need an ordered set 
+*/
+
+static uint make_join_orderinfo(JOIN *join)
 {
   uint i;
   if (join->need_tmp)
@@ -8334,7 +9315,6 @@ uint make_join_orderinfo(JOIN *join)
   return i-1;
 }
 
-
 /*
   Deny usage of join buffer for the specified table
 
@@ -8362,6 +9342,10 @@ void set_join_cache_denial(JOIN_TAB *joi
   if (join_tab->use_join_cache)
   {
     join_tab->use_join_cache= FALSE;
+    /*
+      It could be only sub_select(). It could not be sub_seject_sjm because we
+      don't do join buffering for the first table in sjm nest. 
+    */
     join_tab[-1].next_select= sub_select;
   }
 }
@@ -8389,30 +9373,352 @@ void revise_cache_usage(JOIN_TAB *join_t
   JOIN_TAB *tab;
   JOIN_TAB *first_inner;
 
-  if (join_tab->first_inner)
+  if (join_tab->first_inner)
+  {
+    JOIN_TAB *end_tab= join_tab;
+    for (first_inner= join_tab->first_inner; 
+         first_inner;
+         first_inner= first_inner->first_upper)           
+    {
+      for (tab= end_tab-1; tab >= first_inner; tab--)
+        set_join_cache_denial(tab);
+      end_tab= first_inner;
+    }
+  }
+  else if (join_tab->first_sj_inner_tab)
+  {
+    first_inner= join_tab->first_sj_inner_tab;
+    for (tab= join_tab-1; tab >= first_inner; tab--)
+    {
+      if (tab->first_sj_inner_tab == first_inner)
+        set_join_cache_denial(tab);
+    }
+  }
+  else set_join_cache_denial(join_tab);
+}
+
+/*
+  end_select-compatible function that writes the record into a sjm temptable
+  
+  SYNOPSIS
+    end_sj_materialize()
+      join            The join 
+      join_tab        Last join table
+      end_of_records  FALSE <=> This call is made to pass another record 
+                                combination
+                      TRUE  <=> EOF (no action)
+
+  DESCRIPTION
+    This function is used by semi-join materialization to capture suquery's
+    resultset and write it into the temptable (that is, materialize it).
+
+  NOTE
+    This function is used only for semi-join materialization. Non-semijoin
+    materialization uses different mechanism.
+
+  RETURN 
+